设置
向编译依赖项中添加 resilient 4j 的 Spring Boot 2 Starter。
该模块期望 org.springframework.boot:spring-boot-starter-actuator
和 org.springframework.boot:spring-boot-starter-aop
已经在运行时提供。 如果你在 spring boot2 中使用 webflux,你还需要 io.github.resilience4j:resilience4j-reactor
Groovy
repositories {
jCenter()
}
dependencies {
compile "io.github.resilience4j:resilience4j-spring-boot2:${resilience4jVersion}"
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-starter-aop')
}
示例
Spring Boot 2 中的设置和使用在 demo 中进行了演示.
配置
您可以在 Spring Boot 的 application.yml
配置文件中配置 CircuitBreaker、Retry、RateLimiter、Bulkhead、Thread pool bulkhead 和 TimeLimiter 实例。
例如:
YAML
resilience4j.circuitbreaker:
instances:
backendA:
registerHealthIndicator: true
slidingWindowSize: 100
backendB:
registerHealthIndicator: true
slidingWindowSize: 10
permittedNumberOfCallsInHalfOpenState: 3
slidingWindowType: TIME_BASED
minimumNumberOfCalls: 20
waitDurationInOpenState: 50s
failureRateThreshold: 50
eventConsumerBufferSize: 10
recordFailurePredicate: io.github.robwin.exception.RecordFailurePredicate
resilience4j.retry:
instances:
backendA:
maxAttempts: 3
waitDuration: 10s
enableExponentialBackoff: true
exponentialBackoffMultiplier: 2
retryExceptions:
- org.springframework.web.client.HttpServerErrorException
- java.io.IOException
ignoreExceptions:
- io.github.robwin.exception.BusinessException
backendB:
maxAttempts: 3
waitDuration: 10s
retryExceptions:
- org.springframework.web.client.HttpServerErrorException
- java.io.IOException
ignoreExceptions:
- io.github.robwin.exception.BusinessException
resilience4j.bulkhead:
instances:
backendA:
maxConcurrentCalls: 10
backendB:
maxWaitDuration: 10ms
maxConcurrentCalls: 20
resilience4j.thread-pool-bulkhead:
instances:
backendC:
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
resilience4j.timelimiter:
instances:
backendA:
timeoutDuration: 2s
cancelRunningFuture: true
backendB:
timeoutDuration: 1s
cancelRunningFuture: false
您还可以覆盖默认配置,定义共享配置并在 Spring Boot 的 application.yml
配置文件中覆盖它们。
例如:
YAML
resilience4j.circuitbreaker:
configs:
default:
slidingWindowSize: 100
permittedNumberOfCallsInHalfOpenState: 10
waitDurationInOpenState: 10000
failureRateThreshold: 60
eventConsumerBufferSize: 10
registerHealthIndicator: true
someShared:
slidingWindowSize: 50
permittedNumberOfCallsInHalfOpenState: 10
instances:
backendA:
baseConfig: default
waitDurationInOpenState: 5000
backendB:
baseConfig: someShared
您还可以使用定制器为特定实例名称覆盖特定 CircuitBreaker、Bulkhead、Retry、RateLimiter 或 TimeLimiter 实例的配置。 下面显示了如何在 YAML 文件中覆盖上述配置的 CircuitBreaker backendA 的示例:
Java
@Bean
public CircuitBreakerConfigCustomizer testCustomizer() {
return CircuitBreakerConfigCustomizer
.of("backendA", builder -> builder.slidingWindowSize(100));
}
Resilience4j 有自己的定制器类型,可以如上所示使用:
Resilienc4j 类型 | 实例定制器类 |
Circuit breaker | CircuitBreakerConfigCustomizer |
Retry | RetryConfigCustomizer |
Rate limiter | RateLimiterConfigCustomizer |
Bulkhead | BulkheadConfigCustomizer |
ThreadPoolBulkhead | ThreadPoolBulkheadConfigCustomizer |
Time Limiter | TimeLimiterConfigCustomizer |
注解
Spring Boot2启动器提供了自动配置的注解和AOP aspect。
RateLimiter、Retry、CircuitBreaker 和 Bulkhead 注释支持同步返回类型和异步类型,如 CompletableFuture 和反应类型,如 Spring Reactor 的 Flux 和 Mono(如果你导入了适当的包,如 resilience4j-reactor
)。
Bulkhead 注释有一个 type 属性来定义将使用哪个 Bulkhead 实现。 默认情况下它是信号量,但您可以通过在注解中设置 type 属性来切换到线程池:
Java
@Bulkhead(name = BACKEND, type = Bulkhead.Type.THREADPOOL)
public CompletableFuture<String> doSomethingAsync() throws InterruptedException {
Thread.sleep(500);
return CompletableFuture.completedFuture("Test");
}
回退的方法
回退方法机制的工作原理类似于 try/catch
块。如果配置了一个回退方法,那么每个执行都会转发到一个回退方法执行器。回退方法执行程序正在搜索能够处理异常的最佳匹配的回退方法。类似于 catch 块。
举个例子:
Java
@CircuitBreaker(name = BACKEND, fallbackMethod = "fallback")
@RateLimiter(name = BACKEND)
@Bulkhead(name = BACKEND, fallbackMethod = "fallback")
@Retry(name = BACKEND)
@TimeLimiter(name = BACKEND)
public Mono<String> method(String param1) {
return Mono.error(new NumberFormatException());
}
private Mono<String> fallback(String param1, CallNotPermittedException e) {
return Mono.just("Handled the exception when the CircuitBreaker is open");
}
private Mono<String> fallback(String param1, BulkheadFullException e) {
return Mono.just("Handled the exception when the Bulkhead is full");
}
private Mono<String> fallback(String param1, NumberFormatException e) {
return Mono.just("Handled the NumberFormatException");
}
private Mono<String> fallback(String param1, Exception e) {
return Mono.just("Handled any other exception");
}
重要的是要记住,回退方法应该放在同一个类中,并且必须具有相同的方法签名,只有一个额外的目标异常参数。
如果有多个 fallbackMethod 方法,将调用最接近匹配的方法,例如:
如果您尝试从NumberFormatException
中恢复,将调用带有签名 String fallback(String parameter, NumberFormatException exception)}
的方法。
仅当多个方法具有相同的返回类型并且您想一劳永逸地为它们定义相同的回退方法时,您才可以定义一个带有异常参数的全局回退方法。
Aspect 顺序
Resilience4j Aspects 顺序如下:Retry ( CircuitBreaker ( RateLimiter ( TimeLimiter ( Bulkhead ( Function ) ) ) ) )
所以在最后应用 Retry
(如果需要)。
如果你需要不同的顺序,你必须使用函数链接样式而不是Spring注释样式,或者使用以下属性显式设置aspect 顺序:
Text
- resilience4j.retry.retryAspectOrder
- resilience4j.circuitbreaker.circuitBreakerAspectOrder
- resilience4j.ratelimiter.rateLimiterAspectOrder
- resilience4j.timelimiter.timeLimiterAspectOrder
- resilience4j.bulkhead.bulkheadAspectOrder
例如 - 要使断路器在重试完成后启动,您必须将 retryAspectOrder
属性设置为大于 circuitBreakerAspectOrder
值的值(更高的值 = 更高的优先级)。
YAML
resilience4j:
circuitbreaker:
circuitBreakerAspectOrder: 1
retry:
retryAspectOrder: 2
指标端点(Metrics endpoint)
CircuitBreaker、Retry、RateLimiter、Bulkhead 和 TimeLimiter 指标会自动发布在指标端点上。 要检索可用指标的名称,请向/actuator/metrics
发出 GET 请求。 请参阅 Actuator Metrics 文档 了解更多详情。
JSON
{
"names": [
"resilience4j.circuitbreaker.calls",
"resilience4j.circuitbreaker.buffered.calls",
"resilience4j.circuitbreaker.state",
"resilience4j.circuitbreaker.failure.rate"
]
}
要检索指标,请向/actuator/metrics/{metric.name}
发出 GET 请求。
例如: /actuator/metrics/resilience4j.circuitbreaker.calls
JSON
{
"name": "resilience4j.circuitbreaker.calls",
"measurements": [
{
"statistic": "VALUE",
"value": 3
}
],
"availableTags": [
{
"tag": "kind",
"values": [
"not_permitted",
"successful",
"failed"
]
},
{
"tag": "name",
"values": [
"backendB",
"backendA"
]
}
]
}
当您想在 Prometheus 端点上发布 CircuitBreaker 端点时,您必须添加依赖项 io.micrometer:micrometer-registry-prometheus
。
要检索指标,请向/actuator/prometheus
发出 GET 请求。 更多详细信息请参阅 Micrometer 入门
健康端点(Health endpoint)
Spring Boot Actuator 健康信息可用于检查正在运行的应用程序的状态。 如果生产系统出现严重问题,监控软件通常使用它来提醒某人。
默认情况下,CircuitBreaker 或 RateLimiter 健康指标是禁用的,但您可以通过配置启用它们。 运行状况指标被禁用,因为当断路器处于打开(OPEN)状态时应用程序状态为关闭(DOWN)。 这可能不是你想要的结果。
YAML
management.health.circuitbreakers.enabled: true
management.health.ratelimiters.enabled: true
resilience4j.circuitbreaker:
configs:
default:
registerHealthIndicator: true
resilience4j.ratelimiter:
configs:
instances:
registerHealthIndicator: true
CircuitBreaker 闭合状态映射为 UP,打开状态映射为 DOWN,半打开状态映射为 UNKNOWN。
例如:
JSON
{
"status": "UP",
"details": {
"circuitBreakers": {
"status": "UP",
"details": {
"backendB": {
"status": "UP",
"details": {
"failureRate": "-1.0%",
"failureRateThreshold": "50.0%",
"slowCallRate": "-1.0%",
"slowCallRateThreshold": "100.0%",
"bufferedCalls": 0,
"slowCalls": 0,
"slowFailedCalls": 0,
"failedCalls": 0,
"notPermittedCalls": 0,
"state": "CLOSED"
}
},
"backendA": {
"status": "UP",
"details": {
"failureRate": "-1.0%",
"failureRateThreshold": "50.0%",
"slowCallRate": "-1.0%",
"slowCallRateThreshold": "100.0%",
"bufferedCalls": 0,
"slowCalls": 0,
"slowFailedCalls": 0,
"failedCalls": 0,
"notPermittedCalls": 0,
"state": "CLOSED"
}
}
}
}
}
}
事件端点(Events endpoint)
发出的 CircuitBreaker、Retry、RateLimiter、Bulkhead 和 TimeLimiter 事件存储在单独的循环事件消费者缓冲区中。 事件消费者缓冲区的大小可以在 application.yml 文件 (eventConsumerBufferSize) 中配置。
端点/actuator/circuitbreakers
列出了所有 CircuitBreaker 实例的名称。 该端点也可用于 Retry、RateLimiter、Bulkhead 和 TimeLimiter。
例如:
JSON
{
"circuitBreakers": [
"backendA",
"backendB"
]
}
默认情况下,端点/actuator/circuitbreakerevents
列出所有 CircuitBreaker 实例的最新 100 个发出的事件。 该端点也可用于 Retry、RateLimiter、Bulkhead 和 TimeLimiter。
JSON
{
"circuitBreakerEvents": [
{
"circuitBreakerName": "backendA",
"type": "ERROR",
"creationTime": "2017-01-10T15:39:17.117+01:00[Europe/Berlin]",
"errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception",
"durationInMs": 0
},
{
"circuitBreakerName": "backendA",
"type": "SUCCESS",
"creationTime": "2017-01-10T15:39:20.518+01:00[Europe/Berlin]",
"durationInMs": 0
},
{
"circuitBreakerName": "backendB",
"type": "ERROR",
"creationTime": "2017-01-10T15:41:31.159+01:00[Europe/Berlin]",
"errorMessage": "org.springframework.web.client.HttpServerErrorException: 500 This is a remote exception",
"durationInMs": 0
},
{
"circuitBreakerName": "backendB",
"type": "SUCCESS",
"creationTime": "2017-01-10T15:41:33.526+01:00[Europe/Berlin]",
"durationInMs": 0
}
]
}