内容纲要

环境

  • 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()函数中以返回备用结果。

最后修改日期: 2024年1月15日

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。