Resilience4j------CircuitBreaker

与Hystrix相比,它有以下一些主要的区别:

  1. Hystrix调用必须被封装到HystrixCommand里,而resilience4j以装饰器的方式提供对函数式接口、lambda表达式等的嵌套装饰,因此你可以用简洁的方式组合多种高可用机制
  2. Hystrix的频次统计采用滑动窗口的方式,而resilience4j采用环状缓冲区的方式
  3. 关于熔断器在半开状态时的状态转换,Hystrix仅使用一次执行判定是否进行状态转换,而resilience4j则采用可配置的执行次数与阈值,来决定是否进行状态转换,这种方式提高了熔断机制的稳定性
  4. 关于隔离机制,Hystrix提供基于线程池和信号量的隔离,而resilience4j只提供基于信号量的隔离

熔断 CircuitBreaker

熔断器模式:微软提出来的一种模式:https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589784(v=pandp.10)

Figure 1 - Circuit Breaker states

 

 

初始化熔断器

CircuitBreakerRegistry负责创建和管理熔断器实例CircuitBreaker,它是线程安全的,提供原子性操作。

CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults();

该方式使用默认的全局配置CircuitBreakerConfig创建熔断器实例,你也可以选择使用定制化的配置,可选项有:

  • 触发熔断的失败率阈值
  • 熔断器从打开状态到半开状态的等待时间
  • 熔断器在半开状态时环状缓冲区的大小
  • 熔断器在关闭状态时环状缓冲区的大小
  • 处理熔断器事件的定制监听器CircuitBreakerEventListener
  • 评估异常是否被记录为失败事件的定制谓词函数Predicate

代码如下:

maven:

<dependency>
            <groupId>io.github.resilience4j</groupId>
            <artifactId>resilience4j-circuitbreaker</artifactId>
            <version>0.13.0</version>
        </dependency>
初始化:
private void init() {
  // Create a custom configuration for a CircuitBreaker
 CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
      .failureRateThreshold(50)//触发熔断的失败率阈值,注意是失败率
 .waitDurationInOpenState(Duration.ofMillis(1000)) //熔断器从打开状态到半开状态的等待时间
 .ringBufferSizeInHalfOpenState(2)//熔断器在半开状态时环状缓冲区的大小
 .ringBufferSizeInClosedState(2)//熔断器在关闭状态时环状缓冲区的大小
 .recordFailure(new Predicate<Throwable>() {
        @Override
 public boolean test(Throwable throwable) {
          return false;
 }
      })//评估异常是否被记录为失败事件的定制谓词函数Predicate
 .build();

 // Create a CircuitBreakerRegistry with a custom global configuration
 CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig);

 // 从注册中心获取使用默认配置的熔断器
 CircuitBreaker circuitBreaker_default = circuitBreakerRegistry.circuitBreaker("default");

 // 从注册中心获取使用定制化配置的熔断器
 CircuitBreaker circuitBreaker_custom = circuitBreakerRegistry
      .circuitBreaker("cunstom", circuitBreakerConfig);

 // 你也可以选择不经过注册中心,直接创建熔断器实例:
 CircuitBreaker defaultCircuitBreaker = CircuitBreaker.ofDefaults("direct_default");

 CircuitBreaker customCircuitBreaker = CircuitBreaker.of("direct_custom", circuitBreakerConfig);
}

 

 

熔断器使用方式

熔断器采用装饰器模式,你可以使用CircuitBreaker.decorateCheckedSupplier() / CircuitBreaker.decorateCheckedRunnable() / CircuitBreaker.decorateCheckedFunction() 装饰 Supplier / Runnable / Function / CheckedRunnable / CheckedFunction,然后使用Vavr的Try.of(…) / Try.run(…) 调用被装饰的函数,也可以使用map / flatMap / filter / recover / andThen链接更多的函数。函数链只有在熔断器处于关闭或半开状态时才可以被调用。

private void process() {
  // 创建熔断器
 CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName");

 // 用熔断器包装函数
 CheckedFunction0<String> decoratedSupplier = CircuitBreaker
      .decorateCheckedSupplier(circuitBreaker,
 () -> "This can be any method which returns: 'Hello");

 // 函数链只有在熔断器处于关闭或半开状态时才可以被调用。
 // 链接其它的函数
 Try<String> result = Try.of(decoratedSupplier).map(value -> value + " world'");

 // 如果函数链中的所有函数均调用成功,最终结果为Success<String>
 Assert.assertEquals(result.isSuccess(), true);
 Assert.assertEquals(result.get(), "This can be any method which returns: 'Hello world'");
}

private void process_morecircuitBreaker() {
  // 两个熔断器
 CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName");
 CircuitBreaker anotherCircuitBreaker = CircuitBreaker.ofDefaults("anotherTestName");

 // When I create a Supplier and a Function which are decorated by different CircuitBreakers
 CheckedFunction0<String> decoratedSupplier = CircuitBreaker
      .decorateCheckedSupplier(circuitBreaker, () -> "Hello");

 CheckedFunction1<String, String> decoratedFunction = CircuitBreaker
      .decorateCheckedFunction(anotherCircuitBreaker, (input) -> input + " world");

 // and I chain a function with map
 Try<String> result = Try.of(decoratedSupplier)
      .mapTry(decoratedFunction::apply);

 Assert.assertEquals(result.isSuccess(), true);
 Assert.assertEquals(result.get(), "Hello world");
}

private void process_failure() {
  // 创建一个环状缓冲区大小为2的熔断器
 CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
      .ringBufferSizeInClosedState(2)
      .waitDurationInOpenState(Duration.ofMillis(1000))
      .build();

 CircuitBreaker circuitBreaker = CircuitBreaker.of("testName", circuitBreakerConfig);

 // 模拟一次失败调用
 circuitBreaker.onError(0, new RuntimeException());
 Assert.assertEquals(circuitBreaker.getState(), State.CLOSED);

 // 模拟第二次失败调用
 circuitBreaker.onError(0, new RuntimeException());
 // 失败率超过百分之五十,熔断器被触发
 Assert.assertEquals(circuitBreaker.getState(), State.OPEN);

 // 由于熔断器处于打开状态,调用失败
 Try<String> result = Try
      .of(CircuitBreaker.decorateCheckedSupplier(circuitBreaker, () -> "Hello"))
      .map(value -> value + " world");

 Assert.assertEquals(result.isFailure(), true);
 Assert.assertEquals(result.failed().get().getClass(), CircuitBreakerOpenException.class);
 System.out.println(result.failed().get().getMessage());
}

熔断器降级

/**
 * 熔断器降级
 */
private void process_recover() {

  // 创建熔断器
 CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName");

 // 模拟失败调用,并链接降级函数
 CheckedFunction0<String> checkedSupplier = CircuitBreaker
      .decorateCheckedSupplier(circuitBreaker, () -> {
        throw new RuntimeException("BAM");
 });

 // 降级函数被调用,最终调用结果为成功
 Try<String> result = Try.of(checkedSupplier).recover(throwable -> "hello recovery");
 Assert.assertEquals(result.isSuccess(), true);
 Assert.assertEquals(result.get(), "hello recovery");
}

熔断器失败判定

默认所有异常都被认定为失败事件,你可以定制Predicate的test检查,实现选择性记录,只有该函数返回为true时异常才被认定为失败事件。下例展示了如何忽略除WebServiceException外的所有异常:

private void process_recordfailure() {
  // Given
 CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
      .ringBufferSizeInClosedState(2)
      .ringBufferSizeInHalfOpenState(2)
      .waitDurationInOpenState(Duration.ofMillis(1000))
      /*.recordFailure(throwable ->
 Match(throwable).of(
 Case($(instanceOf(WebServiceException.class)), true),
 Case($(), false)))*/
 .build();
 CircuitBreaker circuitBreaker = CircuitBreaker.of("testName", circuitBreakerConfig);

 // Simulate a failure attempt
 circuitBreaker.onError(0, new WebServiceException());
 // CircuitBreaker is still CLOSED, because 1 failure is allowed
 Assert.assertEquals(circuitBreaker.getState(), CircuitBreaker.State.CLOSED);

 // When
 CheckedRunnable checkedRunnable = CircuitBreaker.decorateCheckedRunnable(circuitBreaker, () -> {
    throw new SocketTimeoutException("BAM!");
 });
 Try result = Try.run(checkedRunnable);

 // Then
 Assert.assertEquals(result.isFailure(), true);
 // CircuitBreaker is still CLOSED, because SocketTimeoutException has not been recorded as a failure
 Assert.assertEquals(circuitBreaker.getState(), State.CLOSED);
 Assert.assertEquals(result.failed().get().getClass(), IOException.class);
}

监听熔断器事件

private void process_events() {
    // 创建熔断器
 CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName");

 circuitBreaker.getEventPublisher()
        .onSuccess(event -> logger.info("onSuccess"))
        .onError(event -> logger.info("onError"))
        .onIgnoredError(event -> logger.info("onIgnoredError"))
        .onReset(event -> logger.info("onReset"))
        .onStateTransition(event -> logger.info("onStateTransition"));
// Or if you want to register a consumer listening to all events, you can do:
 circuitBreaker.getEventPublisher()
        .onEvent(event -> logger.info("onEvent"));

 CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics();
 float failureRate = metrics.getFailureRate();
 int bufferedCalls = metrics.getNumberOfBufferedCalls();
 int failedCalls = metrics.getNumberOfFailedCalls();

 System.out.println("failureRate : " + failureRate + ", bufferedCalls:" + bufferedCalls
        + ", failedCalls:" + failedCalls);
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值