环境
- Java
- SpringBoot
- Gradle
- resilience4j
背景
我是在一个大型项目中接触到熔断机制的。整个项目使用的是微服务架构,并且微服务拆分颗粒度较细。后台前端、to B的app和to C的app分别是3个前端,这3个前端分别对应一个BFF层,每个BFF层调用一个业务上下文的management服务。该management服务仅作为整合多个微服务接口使用,用于调用多个微服务的接口。如下架构图是一个简化版、简易版,仅供用于理解整个微服务的架构:
我们可以看到整个架构非常复杂,前端调用后端接口的调用链很长,可想而知上游的流量也会很大。所以对于常用的服务,诸如user-service之类的,如果该服务器或者接口出现异常时,会影响很大的问题。服务雪崩就是其中之一。
服务雪崩
A服务调用B服务,若B服务挂掉了没有响应,此时A服务内部阻塞无法释放资源也无法返回错误结果。但依然有请求调用A,那么随着请求堆积A服务会被拖垮。最后就是B服务的错误影响到了A服务。
熔断
为了解决上述的问题,就有了熔断机制的引入。当被调用的服务因为某些原因变得不可用时,为了保证调用方的可用性和响应,就会阻止请求发送给出现问题的被调用方,以避免其他服务消耗过多的资源。当出现问题的被调用服务恢复后,再重新恢复调用。这就被称为熔断器/断路器(circuitbreaker)。
状态
断路器有3种状态:
- 关闭(closed):所有请求都可以通过断路器。
- 打开(open):所有请求都会无法通过。该情况发生于,当过去一段时间内/一定数量的请求中,故障率或者超时时间超出设定的阈值后,断路器就会开启。
- 半开(half-open):是断路器的一种中间状态。根据配置不同,可以允许配置的少量请求通过。根据这部分请求的相应情况,断路器会重新回到关闭或者打开状态。
状态转换
resilience4j
若是要在服务器中实现熔断机制,有一些成熟的服务可以使用。Hystrix目前已经停止更新,官方推荐使用resilience4j作为替换。
resilience4j官方文档参考:https://resilience4j.readme.io/docs/getting-started-3
引入resilience4j包
implementation 'org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j'
添加配置
resilience4j.circuitbreaker:
configs:
default: //定义default配置的参数
slidingWindowType: TIME_BASED
slidingWindowSize: 60
minimumNumberOfCalls: 10
failureRateThreshold: 70
slowCallRateThreshold: 50
slowCallDurationThreshold: 10000
waitDurationInOpenState: 120000
permittedNumberOfCallsInHalfOpenState: 5
automaticTransitionFromOpenToHalfOpenEnabled: true
instances:
test: //定义断路器test使用default的配置
baseConfig: default
对于常用的一些断路器配置,如下:
配置 | 说明 |
---|---|
slidingWindowType | 熔断的判断窗口是基于次数(COUNT_BASED)还是基于时间(TIME_BASED) |
slidingWindowSize | 判断为XX次调用,或者为XX秒时间内。在示例中为判断60秒内请求的错误率和超时率 |
minimumNumberOfCalls | 触发断路器判断的最低调用次数,满足了该次数后才会计算故障率。在示例中表示,只有满足了10次请求后,才会计算60秒内的故障率,否则都不会计算,自然不会使断路器变为打开状态。 |
failureRateThreshold | 错误率阈值,超出该错误率后会将断路器置为open状态。单位为% |
slowCallRateThreshold | 超时率阈值,请求的超时率超出后会将断路器置为open状态。单位为% |
slowCallDurationThreshold | 对超时的定义,即超时时间。在示例中指的是超出10000ms的请求会被计算为超时,用以在计算超时率时作为基准判断。 |
waitDurationInOpenState | 断路器在open状态会持续的时间,该时间过后断路器转为半开half_open状态。在示例中为,断路器会使该服务/接口熔断120s不可响应,120s后进入半开状态。 |
permittedNumberOfCallsInHalfOpenState | 在半开状态允许通过的请求数量。 |
automaticTransitionFromOpenToHalfOpenEnabled | 是否在到达时间后自动转为半开状态。 true:120s后断路器自动进入半开状态。 false:120s后第一个到达的请求会使断路器进入半开状态。 |
其他配置可参考官方文档:https://resilience4j.readme.io/docs/circuitbreaker#create-and-configure-a-circuitbreaker
对接口使用注解
@GetMapping("/test")
@CircuitBreaker(name = "test",fallbackMethod = "fallback")
public String test() {
return "test";
}
public String fallback(Throwable t) {
return "fallback";
}
Example讲解
在上述的示例中,我们配置了一个断路器test。这个断路器的参数为:基于时间窗口进行判断,在60s时间内只要有超出10条请求就会判断。当错误率大于70%或者超时10s请求超过50%时,会将断路器置为open状态。打开状态下的断路器在120s内会阻止所有的请求,在120s后自动进入到半开状态。半开状态允许5次请求通过,若5次请求错误率小于70%并且超时率小于50%,则断路器进入到closed状态。否则断路器依然为open状态。
后续通过@CircuitBreaker指定接口test()使用断路器test。也就是说在访问"/test"接口后,该断路器就会生效。并且当断路器为open状态时,就会进入到fallback()函数中以返回备用结果。
留言