002-Spring Cloud Circuit Breaker 学习

Spring Cloud Circuit Breaker 学习

官方文档

https://docs.spring.io/spring-cloud-circuitbreaker/docs/current/reference/html/#usage-documentation

功能分析

配置入口

org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JAutoConfiguration

主要配置了 org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory以及 暴露监控信息

自定义 配置

  1. 定义 Customizer ,把它 添加载到spring 的bean。

  2. 定义 Customizer

  3. 我们还可以 在定义 Customizer 时候 给 Resilience4JCircuitBreakerFactory 添加 CircuitBreakerCustomizer (This can be useful for adding event handlers to Resilience4J circuit breakers.) ,给特定的CircuitBreaker 添加自定义配置,作用优先级 应该高于 resilience4j-spring-boot2 的属性配置

定义 @Bean
public Customizer<Resilience4JCircuitBreakerFactory> slowCustomizer() {
    return factory -> factory.addCircuitBreakerCustomizer(circuitBreaker -> circuitBreaker.getEventPublisher()
    .onError(normalFluxErrorConsumer).onSuccess(normalFluxSuccessConsumer), "normalflux");
}

Resilience4JCircuitBreakerFactory 中的 groupName

  1. 一组 spring 的 CircuitBreaker 共用一个 ExecutorService
@Override
public Resilience4JCircuitBreaker create(String id, String groupName) {
    Assert.hasText(id, "A CircuitBreaker must have an id.");
    Assert.hasText(groupName, "A CircuitBreaker must have a group name.");
    final ExecutorService groupExecutorService = executorServices.computeIfAbsent(groupName,
            group -> Executors.newCachedThreadPool());
    return create(id, groupName, groupExecutorService);
}
  1. groupName 会 生成tags {group=${groupName} } 传给 timeLimiter,circuitBreaker, bulkheadProvider
  2. groupName 会作为 id 传给 bulkheadProvider (默认情形下groupName = ${id} )

Resilience4JCircuitBreaker 介绍

说明

  1. Resilience4JCircuitBreakerFactory create 方法得到 的是 Resilience4JCircuitBreaker
  2. Resilience4JCircuitBreaker 的 run 方法 组合 timeLimiter,circuitbreaker bulkhead

timeLimiter,circuitbreaker,bulkhead 的 组合
bulkheadProvider 存在时候

//org.springframework.cloud.circuitbreaker.resilience4j.Resilience4jBulkheadProvider#run
public <T> T run(String id, Supplier<T> toRun, Function<Throwable, T> fallback, CircuitBreaker circuitBreaker,
			TimeLimiter timeLimiter, io.vavr.collection.Map<String, String> tags) {
    Supplier<CompletionStage<T>> bulkheadCall = decorateBulkhead(id, tags, toRun);
    final Callable<T> timeLimiterCall = decorateTimeLimiter(bulkheadCall, timeLimiter);
    final Callable<T> circuitBreakerCall = circuitBreaker.decorateCallable(timeLimiterCall);
    return Try.of(circuitBreakerCall::call).recover(fallback).get();
}

bulkheadProvider 不存在时候

// org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreaker#run
@Override
public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) {
    final io.vavr.collection.Map<String, String> tags = io.vavr.collection.HashMap.of(CIRCUIT_BREAKER_GROUP_TAG,
            this.groupName);
    TimeLimiter timeLimiter = timeLimiterRegistry.timeLimiter(id, timeLimiterConfig, tags);
    Supplier<Future<T>> futureSupplier = () -> executorService.submit(toRun::get);

    Callable restrictedCall = TimeLimiter.decorateFutureSupplier(timeLimiter, futureSupplier);
    io.github.resilience4j.circuitbreaker.CircuitBreaker defaultCircuitBreaker = registry.circuitBreaker(this.id,
            this.circuitBreakerConfig, tags);
    circuitBreakerCustomizer.ifPresent(customizer -> customizer.customize(defaultCircuitBreaker));

    if (bulkheadProvider != null) {
        ...
    }
    else {
        Callable<T> callable = io.github.resilience4j.circuitbreaker.CircuitBreaker
                .decorateCallable(defaultCircuitBreaker, restrictedCall);
        return Try.of(callable::call).recover(fallback).get();
    }
}

配置介绍

{
  "properties": [
    {
      "defaultValue": "true",
      "name": "spring.cloud.circuitbreaker.resilience4j.enabled",
      "description": "Enables Resilience4J auto-configuration.",
      "type": "java.lang.Boolean"
    },
	{
	  "defaultValue": "true",
	  "name": "spring.cloud.circuitbreaker.resilience4j.blocking.enabled",
	  "description": "Enables blocking Resilience4J auto-configuration.",
	  "type": "java.lang.Boolean"
	},
    {
	  "defaultValue": "true",
	  "name": "spring.cloud.circuitbreaker.resilience4j.reactive.enabled",
	  "description": "Enables ReactiveResilience4J auto-configuration.",
	  "type": "java.lang.Boolean"
    },
	{
	  "defaultValue": "true",
	  "name": "spring.cloud.circuitbreaker.bulkhead.resilience4j.enabled",
	  "description": "Enables to use of the Bulkhead by Resilience4j.",
	  "type": "java.lang.Boolean"
	}
  ]
}
  1. spring.cloud.circuitbreaker.resilience4j.blocking.enabled 和 spring.cloud.circuitbreaker.resilience4j.enabled 作用相同
  2. spring.cloud.circuitbreaker.bulkhead.resilience4j.enabled 可以关闭 bulkhead
启用的 spring 的 circuitbreaker(circuitbreaker timelimiter bulkhead) 的默认配置(重要)

circuitbreaker

需要留意的配置
slowCallDurationThreshold : 默认60s 如果某些逻辑 本来就会超过60s 需要 按需更改 大于60s
ignoreExceptions : 默认[] 如果某些逻辑 抛出业务异常 (如businessException) 需要ignore

全部配置

配置属性默认值描述
failureRateThreshold50以百分比配置失败率阈值。当失败率等于或大于阈值时,断路器状态并关闭变为开启,并进行服务降级。
slowCallRateThreshold100以百分比的方式配置,断路器把调用时间大于slowCallDurationThreshold的调用视为满调用,当慢调用比例大于等于阈值时,断路器开启,并进行服务降级。
slowCallDurationThreshold60000 [ms]配置调用时间的阈值,高于该阈值的呼叫视为慢调用,并增加慢调用比例。
permittedNumberOfCallsInHalfOpenState10断路器在半开状态下允许通过的调用次数。
maxWaitDurationInHalfOpenState0断路器在半开状态下的最长等待时间,超过该配置值的话,断路器会从半开状态恢复为开启状态。配置是0时表示断路器会一直处于半开状态,直到所有允许通过的访问结束。
slidingWindowTypeCOUNT_BASED配置滑动窗口的类型,当断路器关闭时,将调用的结果记录在滑动窗口中。滑动窗口的类型可以是count-based或time-based。如果滑动窗口类型是COUNT_BASED,将会统计记录最近slidingWindowSize次调用的结果。如果是TIME_BASED,将会统计记录最近slidingWindowSize秒的调用结果。
slidingWindowSize100配置滑动窗口的大小。
minimumNumberOfCalls100断路器计算失败率或慢调用率之前所需的最小调用数(每个滑动窗口周期)。例如,如果minimumNumberOfCalls为10,则必须至少记录10个调用,然后才能计算失败率。如果只记录了9次调用,即使所有9次调用都失败,断路器也不会开启。
waitDurationInOpenState60000 [ms]断路器从开启过渡到半开应等待的时间。
automaticTransition
FromOpenToHalfOpenEnabled
false如果设置为true,则意味着断路器将自动从开启状态过渡到半开状态,并且不需要调用来触发转换。创建一个线程来监视断路器的所有实例,以便在WaitDurationInOpenstate之后将它们转换为半开状态。但是,如果设置为false,则只有在发出调用时才会转换到半开,即使在waitDurationInOpenState之后也是如此。这里的优点是没有线程监视所有断路器的状态。
recordExceptionsempty记录为失败并因此增加失败率的异常列表。
除非通过ignoreExceptions显式忽略,否则与列表中某个匹配或继承的异常都将被视为失败。
如果指定异常列表,则所有其他异常均视为成功,除非它们被ignoreExceptions显式忽略。
ignoreExceptionsempty被忽略且既不算失败也不算成功的异常列表。
任何与列表之一匹配或继承的异常都不会被视为失败或成功,即使异常是recordExceptions的一部分。
recordExceptionthrowable -> true·
By default all exceptions are recored as failures.
一个自定义断言,用于评估异常是否应记录为失败。
如果异常应计为失败,则断言必须返回true。如果出断言返回false,应算作成功,除非ignoreExceptions显式忽略异常。
ignoreExceptionthrowable -> false
By default no exception is ignored.
自定义断言来判断一个异常是否应该被忽略,如果应忽略异常,则谓词必须返回true。
如果异常应算作失败,则断言必须返回false。

timelimiter
timeoutDuration : 默认 1s : 超时时间配置 (类型是 Duration),这个配置肯定要改,建议(最少)默认值改成: 10s
cancelRunningFuture : 默认 true: 当 future.get 超时时候(TimeoutException),是否调用 future.cancel 取消异步任务

bulkhead

BulkheadConfig

配置属性默认值描述
maxConcurrentCalls25隔离允许线程并发执行的最大数量
maxWaitDuration0当达到并发调用数量时,新的线程执行时将被阻塞,这个属性表示最长的等待时间。

ThreadPoolBulkheadConfig

配置属性默认值描述
maxThreadPoolSizeRuntime.getRuntime().availableProcessors()Configures the max thread pool size.
coreThreadPoolSizeRuntime.getRuntime().availableProcessors()- 1Configures the core thread pool size
queueCapacity100Configures the core thread pool size
keepAliveDuration20 [ms]When the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.

建议
我觉没必要 刻意默认禁用 bulkhead

spring Resilience4JCircuitBreakerFactory 线程池分析(重要)
Resilience4JCircuitBreakerFactory

成员属性

1.executorService
executorService = Executors.newCachedThreadPool();
说明:

构造
1. 支持自定义该变量
使用
1. create 方法中(不带 groupName 参数) 创建 Resilience4JCircuitBreaker 用到,传给 Resilience4JCircuitBreaker构造方法

2. ConcurrentHashMap<String, ExecutorService> executorServices

构造 和使用
1. 不支持自定义该变量
2. create 方法中(带 groupName 参数) groupExecutorService = executorServices.computeIfAbsent(groupName,
				group -> Executors.newCachedThreadPool()) 然后传给 Resilience4JCircuitBreaker
Resilience4JCircuitBreaker

1.executorService

当 bulkhead 不存在时候 executorService 直接作为执行 业务方法的封装 然后传给 timeLimiter

当 bulkhead 存在的时候 ,则不会使用,使用 bulkhead 自己的线程池。

PS:

  1. Resilience4JCircuitBreaker 的 groupName 会作为 bulkhead 的id,
  2. groupName 如果没传 默认直接和 id相等 因为 Resilience4JCircuitBreakerFactory 有个不带groupName 的create方法。

与 resilience4j-spring-boot2 的关系

Spring Cloud Circuit Breaker 的实现 依赖与 resilience4j-spring-boot2 自动生成的 类(比如: CircuitBreakerRegistry, TimeLimiterRegistry, BulkheadRegistry)。

所以 我们可以直接使用 resilience4j-spring-boot2 的配置格式,优先级高于 spring 自带的 Customizer。但是低于 addCircuitBreakerCustomizer 中的 Customizer。
属性配置demo 如下

resilience4j.circuitbreaker:
 instances:
     backendA:
         registerHealthIndicator: true
         slidingWindowSize: 100
     backendB:
         registerHealthIndicator: true
         slidingWindowSize: 10
         permittedNumberOfCallsInHalfOpenState: 3
         slidingWindowType: TIME_BASED
         recordFailurePredicate: io.github.robwin.exception.RecordFailurePredicate
resilience4j.timelimiter:
 instances:
     backendA:
         timeoutDuration: 2s
         cancelRunningFuture: true
     backendB:
         timeoutDuration: 1s
         cancelRunningFuture: false

为什么 spring 需要增加类 Resilience4jBulkheadProvider

因为 Spring Cloud Circuit Breaker 强制依赖 resilience4j 的 (CircuitBreakerRegistry 和 TimeLimiterRegistry) 但是 把 Bulkhead 作为一个可选功能提供。

扩展

上文中 resilience4j 的 tags 作用是什么??

用作监控指标的tags

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值