Spring Cloud常用组件表
服务名称 | 组件名称 |
---|---|
服务的注册和发现 | eureka、nacos、consul |
服务的负载均衡 | ribbon |
服务的互相调用 | openFeign、dubbo |
服务的容错 | hystrix、sentinel |
服务的网关 | gateway、zuul |
服务配置统一管理 | config-server、nacos、apollo |
服务消息总线 | bus |
服务安全组件 | security、Oauth2.0 |
服务监控 | admin、jvm |
链路追踪 | sleuth+zipkin |
一、eureka 与 zookeeper 的区别
- CAP原则
- C :一致性、多个机器中的数据一致。
- A:可用性,当多个节点中其中某个节点挂掉了,整个集群可以继续对外提供服务。
- P:分区容错性,由于机房网络或者分区等原因会导致各个机器中的数据短暂不一致。
注册与发现框架中,因为物理规律的存在P是无法绕过的,所以P特性是一定存在的。因为,CAP原则无法全部满足,所以注册与发现框架所遵循 CP、AP两种原则,zookeeper 遵循CP数据一致性原则,eureka 遵循AP高可用原则。
二、ribbon 负载均衡
负载均衡的种类
ribbon - 负载均衡策略
三、openFeign
feign 的核心代码就是 使用 jdk 的 proxy 动态代理特性。
openFeign 启动执行流程
openFeign 接口调用内部执行流程
四、hystrix 断路器
为什么需要断路器:
在微服务架构中,我们将项目根据业务功能拆分成一个个独立的服务,服务之间可以相互调用。根据业务需求的不同,每一个独立的服务我们可能部署多个。在项目的使用中可能因为网络、程序异常、硬件主机环境等等原因可能会导致部分服务离线,或者在出现高并发时,会导致服务统一宕机,即雪崩。为了兼容解决这种种情况,所以出现了断路器模型。
断路器机制:
断路器拥有三种状态:开启、关闭、半开。当Hystrix Command请求后端服务失败数量超过一 定比例(默认50%),断路器会切换到开路状态(Open)。这时所有请求会直接失败而不会发送到后端服务。断路器保持在开路状态一段时间后(默认5秒),自动切换到半开路状态(HALF-OPEN)。这时会判断下一次请求的返回情况,如果请求成功,断路器切回闭路状态 (CLOSED),否则重新切换到开路状态(OPEN)。
Fallback:
Fallback即降级操作,当一个请求失败时通过后备方法返回适合业务请求的返回值,一般是通用默认值。
资源隔离:
hystrix 中资源隔离方式主要是 线程池隔离技术 和 信号量隔离技术
为什么要使用资源隔离
避免因对某一个依赖服务的调用接口延迟或失败,导致服务所有的线程资源全部消耗在这个服务的接口调用上,从而导致后续服务请求崩溃。
线程池隔离 和 信号量隔离的区别
线程池隔离:主要关注的是线程资源的隔离。通过给每个任务分配独立的线程,使任务之间相互隔离,避免彼此干扰。
信号量隔离:主要关注的是对共享资源的访问控制。信号量实际上是一种计数器,用于控制对共享资源的并发访问数量。通过控制信号量的许可数,限制对共享资源的并发访问量。
适用场景
线程池隔离适用于将任务彼此隔离开,每个任务都具有独立的执行环境的情况。例如,需要独立处理一些耗时的任务或需要保证任务间不受影响的情况,适于执行并发任务。基本适于99%的业务场景。
信号量隔离适用于需要控制对共享资源的并发访问量控制的情况。例如,限制同时访问某个文件的线程数量。
Hystrix 断路器注解: 参考文章
@HystrixCommand:
- 此注解表示此方法是 hystrix 方法,其中 fallbackMethod 定义回退方法的名称,可以为当前方法 Hystrix 默认命令属性。
- 也就是使用注解的形式配置 Hystrix,简化开发代码编写,更专注于功能的实现。
- HystrixCommandAspect 通过 AOP 拦截所有的 @HystrixCommand 注解的方法,从而使得 @HystrixCommand 能够集成到 Spring boot 中。
@EnableCircuitBreaker
- 等同于@EnableHystrix,启动断路器,开启Hystrix。EnableCircuitBreakerImportSelector是SpringFactoryImportSelector子类。此类在初始化后,会执行selectImports(AnnotationMetadata metadata)的方法。此方法会根据注解启动的注解(这里指@EnableCircuitBreaker)从spring.factories文件中获取其配置需要初始化@Configuration类(这里是org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration),从而最终初始化HystrixCommandAspect 类,从而实现拦截HystrixCommand的功能。
@DefaultProperties
- @DefaultProperties是类(类型)级别的注释,允许为当前类指定Hystrix默认命令属性,如groupKey,threadPoolKey,commandProperties,threadPoolProperties,ignoreExceptions和raiseHystrixExceptions。使用此注解指定的属性,会覆盖在配置文件中定义的默认配置,也将在类中使用@HystrixCommand注解的方法中公用,除非某个方法明确使用相应的@HystrixCommand参数来指定这些属性。
五、Spring Clund Sleuth 链路追踪
在maven中加入zipkin的依赖,zipkin中包含了sleuth 所以不需要单独引入sleuth
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
通过docker-compose启动zipkin服务:
yml
version: '3'
services:
storage:
image: openzipkin/zipkin-elasticsearch6
container_name: elasticsearch
zipkin:
image: openzipkin/zipkin
container_name: zipkin
environment:
- STORAGE_TYPE=elasticsearch
# Point the zipkin at the storage backend
- ES_HOSTS=elasticsearch
# Uncomment to see requests to and from elasticsearch
# - ES_HTTP_LOGGING=BODY
ports:
# Port used for the Zipkin UI and HTTP Api
- 9411:9411
# Uncomment if you set SCRIBE_ENABLED=true
# - 9410:9410
depends_on:
- storage
dependencies:
image: openzipkin/zipkin-dependencies
container_name: dependencies
entrypoint: crond -f
environment:
- STORAGE_TYPE=elasticsearch
- ES_HOSTS=elasticsearch
# Uncomment to see dependency processing logs
# - ZIPKIN_LOG_LEVEL=DEBUG
# Uncomment to adjust memory used by the dependencies job
# - JAVA_OPTS=-verbose:gc -Xms1G -Xmx1G
depends_on:
- storage
在需要链路追踪的服务的application.yml配置文件中加入如下配置:
base-url 为 zipkin服务的连接地址
yml
spring:
zipkin:
base-url: http://127.0.0.1:9411/
sleuth:
sampler:
probability: 1 #配置采样, 默认采集比例为: 0.1 即 10% 所设置的值介于 0 与 1 之间
rate: 10 # 为了使用 速率限制采集器, 选择每秒间
zipkin 服务如下所示:
六、Admin 服务
新增子项目 Admin,POM.xml文件引入 spring-boot-admin 包
xml
<dependencies>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
</dependencies>
并且在Application文件中启动admin服务
java
package com.jyc.admin;
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
@EnableAdminServer
public class AdminServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AdminServiceApplication.class, args);
}
}
在监控项目的application.yml配置监控指标:
yml
management:
endpoints:
web:
exposure:
include: '*' # 监控所有指标,包括 内存、CPU、网络等
项目启动如下图:
七、Gateway 网关 官方文档
Gateway断言规则:
动态路由配置以及断言配置:
自定义全局过滤器:
java
package com.jyc.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class GlobalFilter implements org.springframework.cloud.gateway.filter.GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//过滤通过
chain.filter(exchange);
return null;
}
/**
* 过滤执行排序,返回的数字越小,越先执行
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
八、Gateway 结合 Redis 实现请求量限流
项目POM引入包:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
项目配置(主要是 routes 相关配置):
yml
server:
port: 8888
spring:
application:
name: gateway-service
cloud:
gateway:
enabled: true
discovery:
locator:
enabled: true # 开启动态路由
lower-case-service-id: true # 开启服务名称小写
routes:
- id: login-service-route # 路由 id,保持唯一即可
uri: lb://user-service # uri 统一资源定位符 url 统一资源标识符
predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
- Path=/user/getUserInfoByUserId #匹配规则
filters:
- name: RequestRateLimiter # 过滤器名称
args: # 过滤器参数
key-resolver: '#{@ipKeyResolver}' # 通过 spel 表达式取 ioc 容器中的 bean的值
redis-rate-limiter.replenishRate: 1 # 生成令牌的速度
redis-rate-limiter.burstCapacity: 3 # 桶容量
main:
web-application-type: reactive
redis:
host: localhost
port: 14379
password: 0dnyhuNoC8anRCCM
eureka:
client:
service-url:
defaultZone: http://jyc-master:8802/eureka
registry-fetch-interval-seconds: 3
instance:
hostname: ${HOSTNAME:jyc-master}
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
创建自定义的 keyResolver :
java
package com.jyc.gateway.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import reactor.core.publisher.Mono;
/**
* 限流
*/
@Configuration
public class RequestLimitConfig {
@Bean
@Primary //主候选的
public KeyResolver ipKeyResolver(){
return exchange -> Mono.just(exchange.getRequest().getHeaders().getHost().getHostString());
}
@Bean
public KeyResolver apiKeyResolver(){
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
}