《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 jianshu.com/p/46c1f28825c3 「天地一蜉蝣_6e86」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

resilience4j 是一款 java 平台轻量级容错库,支持熔断、限流、重试等功能。由于Netflix Hystrix 闭源,我们急需一款功能强大的容错工具库,来保护我们的环境。resilience4j 提供了spring boot 的starter,所以集成resilience4j很简单,但是也有一些坑。因此记录一下。

github:https://github.com/resilience4j/resilience4j

官方文档:https://resilience4j.readme.io/docs/circuitbreaker

我使用的是resilience4j 最新版本 0.16.0,spring boot 2.1.6。

相关依赖

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-actuator</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-aop</artifactId>

</dependency>

<dependency>

<groupId>io.github.resilience4j</groupId>

<artifactId>resilience4j-spring-boot2</artifactId>

<version>0.16.0</version>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

配置resilience4j,在spring 中的application.yml 中增加如下配置:

resilience4j.circuitbreaker:

instances:

backendA:

registerHealthIndicator: true

ringBufferSizeInClosedState: 10

ringBufferSizeInHalfOpenState: 3

waitDurationInOpenState: 10s

failureRateThreshold: 50

eventConsumerBufferSize: 2

backendB:

registerHealthIndicator: true

ringBufferSizeInClosedState: 10

ringBufferSizeInHalfOpenState: 3

waitDurationInOpenState: 10s

failureRateThreshold: 50

eventConsumerBufferSize: 2

recordFailurePredicate: io.github.robwin.exception.RecordFailurePredicate

resilience4j.retry:

instances:

backendA:

maxRetryAttempts: 3

waitDuration: 10s

enableExponentialBackoff: true

exponentialBackoffMultiplier: 2

retryExceptions:

- org.springframework.web.client.HttpServerErrorException

ignoreExceptions:

- com.learn.demo.resilience.ResilienceException

- java.io.IOException

backendB:

maxRetryAttempts: 3

waitDuration: 10s

retryExceptions:

- com.learn.demo.resilience.ResilienceException

ignoreExceptions:

- java.io.IOException

resilience4j.bulkhead:

instances:

backendA:

maxConcurrentCall: 10

maxWaitDuration: 20ms

backendB:

maxWaitDuration: 10ms

maxConcurrentCall: 20

resilience4j.thread-pool-bulkhead:

instances:

backendC:

threadPoolProperties:

maxThreadPoolSize: 1

coreThreadPoolSize: 1

queueCapacity: 1

resilience4j.ratelimiter:

instances:

backendA:

limitForPeriod: 10

limitRefreshPeriod: 1s

timeoutDuration: 0

registerHealthIndicator: true

eventConsumerBufferSize: 100

backendB:

limitForPeriod: 6

limitRefreshPeriod: 500ms

timeoutDuration: 3s

server:

port: 9090

注意

resilience4j 的配置在0.16.0 发生了一下变化。网上一些文档都是基于0.13.0版本。还有0.16.0版本配置不能被IDEA 识别,也不能自动联想,所以使用0.16.0版本尽量参考官网的配置。

熔断

配置介绍

配置 默认值 描述
failureRateThreshold 50 故障率阈值(百分比),超过该阈值,CircuitBreaker 触发熔断
ringBufferSizeInHalfOpenState10CircuitBreaker 半开时环形缓冲区的大小。当CircuitBreaker从断开状态转换为半开状态,使用此环形缓冲器以确定是否健康。
ringBufferSizeInClosedState 100 CircuitBreaker关闭时环形缓冲区的大小,在计算故障率之前,需要填充环形缓冲区。
waitDurationInOpenState 60s CircuitBreaker在从open打开到半打开之前应该等待的时间。
automaticTransitionFromOpenToHalfOpenEnabled false 是否自动有open 切换到half open
recordExceptions null 失败异常
ignoreExceptions null 需要忽略的异常
recordFailure throwable -> true 自定义失败判定条件函数,默认所有异常都为失败

注解

@CircuitBreaker(name = “backendA”)

code

@Retry(name = “backendA”)

@CircuitBreaker(name = “backendA”)

@RateLimiter(name = “backendA”)

@Service

public class ServiceA {

@Bulkhead(name = "backendA")

public String sucess(){

System.out.println("sucess a");

return "sucess a";

}

@Bulkhead(name = "backendA")

public String fail() throws ResilienceException {

throw new ResilienceException("fail a");

}

}

多次失败达到阈值之后,再调用会抛出异常

io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker ‘backendA’ is OPEN and does not permit further calls

rest 调用返回结果:

{

"timestamp": "2019-07-10T09:45:21.065+0000",

"status": 500,

"error": "Internal Server Error",

"message": "CircuitBreaker 'backendA' is OPEN and does not permit further calls",

"path": "/serviceA/failed"

}

这种情况可以配合spring aop,拦截异常,返回特性http 状态码或者信息,让前端捕获特定http 状态码,以此来呈现熔断之后的ui。

限流

配置

配置 默认值 描述
timeoutDuration 5s 线程等待时间
limitRefreshPeriod 500ns 令牌刷新周期
limitForPeriod 50 一个周期内令牌数

注解

@RateLimiter(name = “backendA”)

code

同上

达到限制时抛出异常

io.github.resilience4j.ratelimiter.RequestNotPermitted: RateLimiter ‘backendA’ does not permit further calls

注意

经过试验,当@RateLimiter和@CircuitBreaker一起使用时,需要熔断器增加忽略RequestNotPermitted异常。否则会触发熔断。

ignoreExceptions:

  • io.github.resilience4j.ratelimiter.RequestNotPermitted

隔离(bulkhead)

其主要作用是限制并发次数

配置

配置 默认值 描述
maxConcurrentCalls 25 最大并发数
maxWaitDuration 0 饱和时等待时间

注解

@Bulkhead(name = “backendA”)

重试

配置

配置 默认值 描述
maxAttempts 3 最大尝试次数
waitDuration 500ms 等待间隔
intervalFunction numOfAttempts - > waitDuration 故障后等待时间函数,默认为waitDuration,也可以通过函数修改为指数增长
retryOnResultPredicate 判断结果是否重试Predicate
retryOnExceptionPredicate 判断异常是否重试Predicate
retryExceptions 重试异常列表
ignoreExceptions 忽略异常列表

注解

@Retry(name = “backendA”)

resilience4j 为我们提供了很棒的容错库,简单易用。

文章目录
  1. 1. 注意
  • 熔断
  • 限流
    1. 1. 注意
  • 隔离(bulkhead)