CircuitBreaker–Resilience4J(熔断)介绍和使用
CircuitBreaker介绍
CircuitBreaker支持的实现方式:Sentinel,Resilience4J ,Spring Retry
CircuitBreaker只是一套规范和接口,落地实现者是Reslience4J
实现原理:
CircuitBreaker的目的是保护分布式系统免受故障和异常,提高系统的可用性和健壮性。
当一个组件或服务出现故障时,CircuitBreaker会迅速切换到开放OPEN状态(保险丝跳闸断电),阻止请求发送到该组件或服务从而避免更多的请求发送到该组件或服务。这可以减少对该组件或服务的负载,防止该组件或服务进一步崩溃,并使整个系统能够继续正常运行。同时,CircuitBreaker还可以提高系统的可用性和健壮性,因为它可以在分布式系统的各个组件之间自动切换,从而避免单点故障的问题。
有三种状态 :close ,open, half open
当超过定义数量的请求时,断路器会从close --》open,此时请求无法再访问服务,过一小段时间,会尝试恢复close,此时是 half open 状态,如果尝试成功 就会恢复为close状态,如果失败 就会熔断并进入服务降级。
示例
*# 6次访问中当执行方法的失败率达到50%时CircuitBreaker将进入开启OPEN状态(保险丝跳闸断电)拒绝所有请求。
#*等待5秒后,CircuitBreaker将自动从开启OPEN状态过渡到半开HALF_OPEN状态,允许一些请求通过以测试服务是否恢复正常。
- *如还是异常 *CircuitBreaker 将重新进入开启OPEN状态;如正常将进入关闭CLOSE闭合状态恢复正常处理请求。
Resilience4J
Resilience4J官网https://github.com/lmhmhl/Resilience4j-Guides-Chinese/blob/main/index.md
yaml配置参数
failure-rate-threshold | 以百分比配置失败率峰值 |
---|---|
sliding-window-type | 断路器的滑动窗口期类型 可以基于“次数”(COUNT_BASED)或者“时间”(TIME_BASED)进行熔断,默认是COUNT_BASED。 |
sliding-window-size | **若COUNT_BASED,则10次调用中有50%失败(即5次)打开熔断断路器;**若为TIME_BASED则,此时还有额外的两个设置属性,含义为:在N秒内(sliding-window-size)100%(slow-call-rate-threshold)的请求超过N秒(slow-call-duration-threshold)打开断路器。 |
slowCallRateThreshold | 以百分比的方式配置,断路器把调用时间大于slowCallDurationThreshold的调用视为慢调用,当慢调用比例大于等于峰值时,断路器开启,并进入服务降级。 |
slowCallDurationThreshold | 配置调用时间的峰值,高于该峰值的视为慢调用。 |
permitted-number-of-calls-in-half-open-state | 运行断路器在HALF_OPEN状态下时进行N次调用,如果故障或慢速调用仍然高于阈值,断路器再次进入打开状态。 |
minimum-number-of-calls | 在每个滑动窗口期样本数,配置断路器计算错误率或者慢调用率的最小调用数。比如设置为5意味着,在计算故障率之前,必须至少调用5次。如果只记录了4次,即使4次都失败了,断路器也不会进入到打开状态。 |
wait-duration-in-open-state | 从OPEN到HALF_OPEN状态需要等待的时间 |
使用方法
maven依赖
<!--resilience4j-circuitbreaker-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<!-- 由于断路保护等需要AOP实现,所以必须导入AOP包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
application.yaml配置
spring:
cloud:
circuitbreaker:
enabled: true
group:
enabled: true #没开分组永远不用分组的配置。精确优先、分组次之(开了分组)、默认最后
# Resilience4j CircuitBreaker 按照次数:COUNT_BASED 的例子
# 6次访问中当执行方法的失败率达到50%时CircuitBreaker将进入开启OPEN状态(保险丝跳闸断电)拒绝所有请求。
# 等待5秒后,CircuitBreaker 将自动从开启OPEN状态过渡到半开HALF_OPEN状态,允许一些请求通过以测试服务是否恢复正常。
# 如还是异常CircuitBreaker 将重新进入开启OPEN状态;如正常将进入关闭CLOSE闭合状态恢复正常处理请求。
# Resilience4j CircuitBreaker 按照时间:TIME_BASED 的例子
resilience4j:
timelimiter:
configs:
default:
timeout-duration: 10s #神坑的位置,timelimiter 默认限制远程1s,超于1s就超时异常,配置了降级,就走降级逻辑
circuitbreaker:
configs:
default:
failureRateThreshold: 50 #设置50%的调用失败时打开断路器,超过失败请求百分⽐CircuitBreaker变为OPEN状态。
slowCallDurationThreshold: 2s #慢调用时间阈值,高于这个阈值的视为慢调用并增加慢调用比例。
slowCallRateThreshold: 30 #慢调用百分比峰值,断路器把调用时间⼤于slowCallDurationThreshold,视为慢调用,当慢调用比例高于阈值,断路器打开,并开启服务降级
slidingWindowType: TIME_BASED # 滑动窗口的类型
slidingWindowSize: 2 #滑动窗口的大小配置,配置TIME_BASED表示2秒
minimumNumberOfCalls: 2 #断路器计算失败率或慢调用率之前所需的最小样本(每个滑动窗口周期)。
permittedNumberOfCallsInHalfOpenState: 2 #半开状态允许的最大请求数,默认值为10。
waitDurationInOpenState: 5s #从OPEN到HALF_OPEN状态需要等待的时间
recordExceptions:
- java.lang.Exception
instances:
cloud-payment-service:
baseConfig: default
基 于 时 间 的 滑 动 窗 口
基于时间的滑动窗口是一种用于处理具有N个价值的环形数组的方法。例如,一个滑动窗口的大小为1秒,环形数组总是有固定数量的桶,每个桶统计了在相应一秒内发生的所有事件的结果(部分统计结果)。数组中的第一个桶存储了当前一秒内所有事件的结果,而其他的桶则存储了之前每秒的结果。
滑动窗口不会单独存储所有的结果,而是对每个桶内的统计结果进行增量式的更新。当新的事件结果被记录时,总的统计值会被增量更新。
检索快照(总的统计值)的时间复杂度为O(1),因为快照已经预先统计好了,并且与滑动窗口的大小无关。
关于此方法实现的空间需求(存储消耗)约等于(待补充)。由于每次事件结果(元组)不会被单独存储,只是对N个桶进行单独统计和一次总的统计。
每个桶内部分包括三个整型变量用于计算失效数、命中数、总调用数。还有一个长整型变量用于存储所有调用的响应时间。
application.yaml配置
spring:
cloud:
circuitbreaker:
enabled: true
group:
enabled: true #没开分组永远不用分组的配置。精确优先、分组次之(开了分组)、默认最后
# Resilience4j CircuitBreaker 按照次数:COUNT_BASED 的例子
# 6次访问中当执行方法的失败率达到50%时CircuitBreaker将进入开启OPEN状态(保险丝跳闸断电)拒绝所有请求。
# 等待5秒后,CircuitBreaker 将自动从开启OPEN状态过渡到半开HALF_OPEN状态,允许一些请求通过以测试服务是否恢复正常。
# 如还是异常CircuitBreaker 将重新进入开启OPEN状态;如正常将进入关闭CLOSE闭合状态恢复正常处理请求。
# Resilience4j CircuitBreaker 按照时间:TIME_BASED 的例子
# Resilience4j CircuitBreaker 按照时间:TIME_BASED 的例子
resilience4j:
timelimiter:
configs:
default:
timeout-duration: 10s #神坑的位置,timelimiter 默认限制远程1s,超于1s就超时异常,配置了降级,就走降级逻辑
circuitbreaker:
configs:
default:
failureRateThreshold: 50 #设置50%的调用失败时打开断路器,超过失败请求百分⽐CircuitBreaker变为OPEN状态。
slowCallDurationThreshold: 2s #慢调用时间阈值,高于这个阈值的视为慢调用并增加慢调用比例。
slowCallRateThreshold: 30 #慢调用百分比峰值,断路器把调用时间⼤于slowCallDurationThreshold,视为慢调用,当慢调用比例高于阈值,断路器打开,并开启服务降级
slidingWindowType: TIME_BASED # 滑动窗口的类型
slidingWindowSize: 2 #滑动窗口的大小配置,配置TIME_BASED表示2秒
minimumNumberOfCalls: 2 #断路器计算失败率或慢调用率之前所需的最小样本(每个滑动窗口周期)。
permittedNumberOfCallsInHalfOpenState: 2 #半开状态允许的最大请求数,默认值为10。
waitDurationInOpenState: 5s #从OPEN到HALF_OPEN状态需要等待的时间
recordExceptions:
- java.lang.Exception
instances:
cloud-payment-service:
baseConfig: default
总结:断路器开启或者关闭的条件
当满足一定的峰值和失败率会进入open状态
open状态时,不会调用主业务逻辑,会直接调用fallback方法 进入服务降级
一段时间之后,这个时候断路器会从OPEN进入到HALF_OPEN半开状态,会放几个请求过去探探链路是否通?
如成功,断路器会关闭CLOSE(类似保险丝闭合,恢复可用);
如失败,继续开启。重复上述
建议使用按数量滑动窗口使用