微服务实践(七)熔断降级

服务熔断降级概念

服务熔断服务降级是分布式系统中常见的容错机制。

服务熔断指的是在一段时间内,如果一个服务的请求失败率超过了设定的阈值,系统就会自动短路,不再调用该服务,而是直接返回错误响应或者调用 fallback 逻辑,以减少对该服务的负载,防止服务雪崩的发生。当服务熔断后,当服务调用出现问题时,服务消费方可以快速响应,避免等待超时和资源浪费。

服务降级是指当服务的某个功能出现故障或异常时,提供一个备用的功能来代替原始功能,保证服务可用性。

熔断降级框架

Hystrix

Hystrix是Netflix开源的一款熔断降级框架,功能非常丰富,包括线程池隔离、信号量隔离、熔断、降级等。但是Hystrix的维护已经停止,不再提供新的功能和Bug修复。

1.在 pom.xml 文件中添加 的依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>{version}</version>
</dependency>

2.在FeignClient接口的注解中添加fallback属性,指定降级类,例如:

@FeignClient(name = "user-service", fallback = UserFallbackFactory.class)
public interface UserFeignClient {

    @GetMapping("/users/{id}")
    User findById(@PathVariable Long id);
}
@Component
public class UserFallbackFactory implements FallbackFactory<UserFeignClient> {
    @Override
    public UserFeignClient create(Throwable cause) {
        return new UserFeignClient() {
            @Override
            public UserfindById() {
                 // 降级逻辑
              return new User(id, "default", "123456");
            }
        };
    }
}

3.在配置文件中添加Hystrix的相关配置,例如:

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000 # 设置超时时间
      circuitBreaker:
        enabled: true # 开启熔断
        requestVolumeThreshold: 10 # 熔断请求阈值
        errorThresholdPercentage: 60 # 错误率阈值
        sleepWindowInMilliseconds: 5000 # 熔断器开启时间

4.开启Hystrix的Feign支持,如下所示:

feign:
  hystrix:
    enabled: true

5.这样就完成了熔断的配置。

注意:Hystrix相关依赖和配置写在调用方,它是用于熔断和降级的功能,这些功能通常是由调用方控制和触发的。被调用方可能没有意识到是否需要熔断或降级

下面是Hystrix熔断器的一些常见配置参数及其含义:

  1. circuitBreaker.enabled: 是否启用断路器,默认为 true。
  2. circuitBreaker.requestVolumeThreshold: 在滚动时间窗口中,请求数量的阈值,达到该阈值后才会进行熔断计算。默认为 20。
  3. circuitBreaker.errorThresholdPercentage: 断路器打开的错误百分比阈值,默认为 50。
  4. circuitBreaker.sleepWindowInMilliseconds: 断路器打开后,在该时间窗口内,所有请求都将直接返回失败(即被降级或者抛出异常),而不会尝试执行远程调用。默认为 5000 毫秒。
  5. metrics.rollingStats.timeInMilliseconds: 滚动时间窗口的持续时间(以毫秒为单位),用于统计断路器指标的时间跨度。默认为 10000 毫秒。
  6. metrics.rollingStats.numBuckets: 滚动时间窗口被分成的桶数,默认为 10。
  7. execution.isolation.thread.timeoutInMilliseconds: 服务调用的超时时间,默认为 1000 毫秒。
  8. fallback.enabled: 是否启用服务降级,默认为 true。
  9. fallback.isolation.semaphore.maxConcurrentRequests: 当服务降级启用时,最大的并发降级请求数,默认为 10。
  10. requestCache.enabled: 是否启用请求缓存,默认为 true。

以上只是一部分常用的配置参数,更多详细的配置参数可以参考Hystrix 官方文档

2.Resilience4j

在 Spring Cloud 2020 版本之后,Spring Cloud 对 OpenFeign 进行了更新,官方提供了一种新的方式来实现服务熔断,即通过 Resilience4j 库实现。相较于 Hystrix,Resilience4j 是一个轻量级的库,它具有更快的性能,更好的扩展性,更多的配置项,以及更好的响应式支持。下面简单介绍一下如何使用:

1.添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-cloud2</artifactId>
    <version>1.7.0</version>
</dependency>

2.配置文件启用circuitbreaker

spring:
  application:
    name: user-service
  cloud:
    circuitbreaker:
      enabled: true # 开启 Resilience4j 
feign:
  hystrix:
    enabled: false # 关闭 Hystrix

3.定义 Feign 接口

@FeignClient(name = "user-service", fallback = UserFallbackFactory.class)
public interface UserFeignClient {

    @GetMapping("/users/{id}")
    User findById(@PathVariable Long id);
}

4.定义降级逻辑

@Component
public class UserFallbackFactory implements FallbackFactory<UserFeignClient> {
    @Override
    public UserFeignClient create(Throwable cause) {
        return new UserFeignClient() {
            @Override
            public UserfindById() {
                 // 降级逻辑
              return new User(id, "default", "123456");
            }
        };
    }
}

5.配置熔断器

@Configuration
public class CircuitBreakerConfig {

    @Bean
    public Customizer<Resilience4JCircuitBreakerFactory> globalCustomConfiguration() {
        CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
                .failureRateThreshold(50)
                .waitDurationInOpenState(Duration.ofSeconds(10))
                .ringBufferSizeInClosedState(100)
                .build();

        return factory -> {
            factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
                    .circuitBreakerConfig(circuitBreakerConfig)
                    .timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(5)).build())
                    .build());
            factory.addCircuitBreakerCustomizer(cb -> cb.getEventPublisher()
                    .onStateTransition(event -> System.out.println("Circuit breaker " + event.getCircuitBreakerName()
                            + " changed state from " + event.getStateTransition().getFromState()
                            + " to " + event.getStateTransition().getToState())));
        };
    }
}

在上面的示例中,我们通过 CircuitBreakerConfig 配置了熔断器的参数,然后通过 Customizer 对象全局配置了 Resilience4j 的断路器,包括熔断器和限流器。在 CircuitBreakerConfig 类中,我们还注册了一个熔断器事件监听器,可以监听熔断器状态的变化。在 Feign 接口中,我们通过 fallback 属性指定了降级逻辑类,在服务不可用时会执行该类的降级逻辑。

Resilience4JCircuitBreakerFactory的常用配置项解读:

  1. CircuitBreakerConfig: 配置熔断器的参数,例如故障率、时间窗口等。包括以下参数:
  • failureRateThreshold:故障率阈值,默认值为50,表示当请求的失败率超过50%时,触发熔断器的open状态
  • slowCallRateThreshold:慢调用率阈值,默认值为100,表示当慢调用率(慢调用指的是耗时超过阈值的调用)超过100%时,触发熔断器的open状态
  • permittedNumberOfCallsInHalfOpenState:半开状态下允许的最大请求次数,默认值为10
  • slidingWindowSize:滑动窗口大小,默认值为100
  • minimumNumberOfCalls:最小请求数量,默认值为100,当请求数量小于此值时,熔断器不会打开
  • waitDurationInOpenState:open状态持续时间,默认为60秒
  • automaticTransitionFromOpenToHalfOpenEnabled:是否允许open状态自动转换为half-open状态,默认为true
  • writableStackTraceEnabled:是否允许记录异常栈信息,默认为false
  1. TimeLimiterConfig:配置时间限制器的参数,包括以下参数:
  • timeoutDuration:调用超时时间,默认为1秒
  1. BulkheadConfig:配置隔离器的参数,包括以下参数:
  • maxConcurrentCalls:最大并发请求数,默认为25
  • maxWaitDuration:最大等待时间,默认为0,表示无限等待
  • maxQueueSize:等待队列大小,默认为100
  1. RetryConfig:配置重试的参数,包括以下参数:
  • maxAttempts:最大重试次数,默认为3
  • waitDuration:重试等待时间,默认为500ms
  • retryExceptions:需要重试的异常类型,默认为全部异常类型