在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,如何保证一个依赖出问题的情况下 不会导致整体服务失败,避免级联故障?
resilience4j提供了三种服务熔断和降级
1、断路器
“断路器"本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FalBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
断路器作用
当A服务调用B服务时,B服务出现故障,A服务多次调用失败或调用时间超出阈值后会切断与B服务的调用关系并触发兜底方法、一段时间后A服务会进入半开状态,放少量的请求通过,如果这些请求成功率到达一定比例时则会重新连接B服务的调用关系,反之则继续断开,反复尝试
CircuitBreaker
断路器的状态
总结
断路器开启或关闭的条件
1、当满足一定峰值和失败率达到一定条件时,断路器将会进入open状态,服务熔断
2、当open状态时,所有请求都不会再调用主业务逻辑方法,而是走fallbackmetnod兜底方法,服务降级
3、一段时间后(个人设置时间),熔断器会从open状态进入到half_open状态,这时会放几个请求过去(具体几个也是个人设置)看看链路是否通,如果成功则会关闭熔断器(close)恢复主业务方法调用,如果失败,继续开启熔断器,重复上述
SpringCloud整合resilience4j 1、导入对应坐标(resilience4j需要使用到aop)
<!--resilience4j-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、在yml文件中配置开启服务熔断
2.1开启熔断器
# 开启断路器
circuit breaker:
enabled: true
group:
enabled: true
2.2.1 配置熔断器(请求熔断器)
resilience4j:
circuit breaker:
configs:
default:
failure-rate-threshold: 50 #设置失败比例 请求失败比例超过50%打开断路器
sliding-window-type: COUNT_BASED # 设置滑动窗口类型,按请求次数判断是否打开断路器
sliding-window-size: 6 # 滑动窗口大小 请求次数
minimum-number-of-calls: 6 # 最小样本数,最少要有6次请求失败才会计算失败率,及时5次请求5次失败也不会触发断路器
automatic-transition-from-open-to-half-open-enabled: true # 断路器开启后,会自动执行到半开状态重新发起请求测试,成功断路器关闭,失败断路器继续开启
wait-duration-in-open-state: 5s #断路器开启5秒后进入半开状态,测试服务是否可用
permitted-number-of-calls-in-half-open-state: 2 #断路器半开状态下最多允许2个请求进行测试,如果其中有任何一个失败,断路器依旧开启状态
record-exceptions:
- java.lang.Exception # 记入异常
instances:
cloud-payment-service: # 这个要与服务模块保持一致
base-config: default
2.2.2 配置熔断器(时间熔断器)
resilience4j:
time limiter:
configs:
default:
timeout-duration: 10s
circuit breaker:
configs:
default:
failure-rate-threshold: 50 # 设置失败比例 请求失败比例超过50%打开断路器
slow-call-duration-threshold: 2s #慢调用阈值,请求超过2秒即视为慢调用
slow-call-rate-threshold: 30 # 当慢调用次数超过30% 开启断路器
sliding-window-type: TIME_BASED #设置滑动窗口类型
sliding-window-size: 2 #滑动窗口大小配置 2秒
minimum-number-of-calls: 2 #最小样本数量,在计算失败率或者慢调用比例之前最少需要有两个样本
permitted-number-of-calls-in-half-open-state: 2 #在断路器半开状态允许两个请求
wait-duration-in-open-state: 5s # 断路器从打开状态到半开状态的间隔时间为5s
record-exceptions:
- java.lang.Exception
instances:
cloud-payment-service: # 这个要与服务模块保持一致
baseConfig: default
3、编写controller
2、舱壁隔板 BulkHead(信号量舱壁)与FixedThreadPoolBulkHead(固定线程池舱壁)
舱壁隔板的作用
当请求数量达到一定阈值时会限制请求访问,被限制的请求会等待、等待超时会触发兜底方法,避免大量请求压垮系统 (比如说系统只接受20个请求过来处理、其他请求过来就需要等待,如果等待期间有请求处理完了等待请求就会进入,如果超时就会触发兜底方法)
SpringCloud整合BulkHead(信号量舱壁)
1、导入坐标
maven
复制代码
<!--BulkHead舱壁-->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-bulkhead</artifactId>
</dependency>
2、yml配置BulkHead
3、创建controller调用中间模块的api
SpringCloud整合FixedThreadPoolBulkHead(固定线程池舱壁)
1、导入坐标
<!--BulkHead舱壁-->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-bulkhead</artifactId>
</dependency>
2、yml配置BulkHead
3、创建controller调用中间模块api
3、限流
限流的作用
当用户在同一时间多次访问同一个请求数量达到一定阈值时会对该请求进行限制访问,直到刷新最大访问数量时才可以继续请求,(隔板和限流的区别、隔板是针对所有用户的请求进行限制,限流是针对单个用户的请求进行限制)
常见的限流算法
漏桶算法
缺点
令牌桶算法
滚动时间窗口算法
缺点(双杀) 在即将进入下一个计算周期时突然出现大量请求,同时刚好进入下一个计算周期也进入大量请求,导致系统在一个计算周期承受双倍的请求压力导致系统崩溃
滑动时间窗口算法 (将一半的请求放到下一个周期进行处理)
SpringCloud整合RateLimiter
1、导入坐标
<!--RateLimiter-->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-ratelimiter</artifactId>
</dependency>
2、在yml文件配置
3、创建controller