Resilience4J 介绍
Netflix Hystrix 断路器是 Spring Cloud 中最早就开始支持的一种服务调用容错解决方案,但是目前的 Hystrix 已经处于维护模式了,虽然这并不影响已经上线的项目,并且在短期内,你甚至也可以继续在项目中使用 Hystrix 。但是长远来看,处于维护状态的 Hystrix 走下历史舞台只是一个时间问题,特别是在 Spring Cloud Greenwich 版中,官方已经给出了 Hystrix 的建议替代方案。如下图:
Resilience4j 是 Spring Cloud Greenwich 版推荐的容错解决方案,它是一个轻量级的容错库,受 Netflix Hystrix 的启发而设计,它专为 Java 8 和函数式编程而设计。
Resilience4j 非常轻量级,因为它的库只使用 Vavr (以前称为 Javaslang ),它没有任何其他外部库依赖项。相比之下, Netflix Hystrix 对Archaius 具有编译依赖性,这导致了更多的外部库依赖,例如 Guava 和 Apache Commons 。而如果使用Resilience4j,你无需引用全部依赖,可以根据自己需要的功能引用相关的模块即可。
Resilience4j 也提供了一系列增强微服务可用性的功能,主要功能如下:
- 断路器
- 限流
- 基于信号量的隔离
- 缓存
- 限时
- 请求重试
接下来,我们就先来看通过一个普通的Maven项目来看 Resilience4j 中这几个功能的基本用法。
上面提到的 Resilience4j 中的功能,每一个功能都对应了一个依赖。我们创建好Maven项目后,再添加单元测试依赖:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>
一、Resilience4j 的功能介绍
断路器有三种正常状态:完全打开OPEN,半开HALF_OPEN,关闭CLOSED,还有两种通过设置的强制状态:强制不可用DISABLED,强制打开FORCED_OPEN。
断路器初始化
使用 Resilience4j 提供的断路器功能,需要我们首先加入如下依赖:
<dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-circuitbreaker</artifactId> <version>1.5.0</version> </dependency>
这个库提供了一个基于 ConcurrentHashMap 的 CircuitBreakerRegistry ,CircuitBreakerRegistry 是线程安全的,并且是原子操作。开发者可以使用 CircuitBreakerRegistry 来创建和检索 CircuitBreaker 的实例 ,开发者可以直接使用默认的全局CircuitBreakerConfig 为所有 CircuitBreaker 实例创建 CircuitBreakerRegistry ,如下所示:
CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults();
当然开发者也可以提供自己的 CircuitBreakerConfig ,然后根据自定义的 CircuitBreakerConfig 来创建一个 CircuitBreakerRegistry 实例,进而创建 CircuitBreaker 实例。如果我们使用自定义的 CircuitBreakerConfig :
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .failureRateThreshold(50) //默认为50,即失败率阈值为50%, 超过这个阈值,断路器就会打开 .waitDurationInOpenState(Duration.ofMillis(1000)) // 用来指定断路器从OPEN到HALF_OPEN状态等待的时长,默认是60秒 .permittedNumberOfCallsInHalfOpenState(2) //熔断器半开时的限制线程的并发量 .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) // 滑动窗口类型,有基于时间TIME_BASED和基于计数COUNT_BASED .slidingWindowSize(2) //滑动窗口大小,默认是基于计数的滑动窗口类型 .automaticTransitionFromOpenToHalfOpenEnabled(false) //当waitDurationInOpenState时间一过,是否自动从OPEN切换到HALF_OPEN,默认为false .build(); // 配置CircuitBreakerRegistry CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig); // 创建两个断路器 CircuitBreaker circuitBreaker2 = circuitBreakerRegistry.circuitBreaker("otherName"); CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("uniqueName", circuitBreakerConfig);
如果开发者不想使用 CircuitBreakerRegistry 来管理断路器,那么也可以直接创建一个 CircuitBreaker 对象,创建方式如下:
CircuitBreaker defaultCircuitBreaker = CircuitBreaker.ofDefaults("testName");
CircuitBreaker customCircuitBreaker = CircuitBreaker.of("testName", circuitBreakerConfig);
断路器使用案例
断路器使用了装饰者模式,开发者可以使用 CircuitBreaker.decorateCheckedSupplier(), CircuitBreaker.decorateCheckedRunnable() 或者 CircuitBreaker.decorateCheckedFunction() 来装饰 Supplier / Runnable / Function 或者 CheckedRunnable / CheckedFunction,然后使用 Try.of(…) 或者 Try.run(…) 来进行调用操作,也可以使用 map、flatMap、filter、recover 或者 andThen 进行链式调用,但是调用这些方法断路器必须处于 CLOSED 或者 HALF_OPEN 状态。例如下面一个例子,创建一个断路器出来,首先装饰了一个函数,这个函数返回一段字符串,然后使用 Try.of 去执行,执行完后再进入到 map 中去执行。如果第一个函数正常执行第二个函数才会执行,如果第一个函数执行失败,那么 map 函数将不会执行。