Resilience4j 熔断器详解
简介
什么是 Resilience4j
Resilience4j 是一个轻量级的容错库,专为 Java 8 和函数式编程设计。它提供了一系列高阶函数(装饰器),用于增强任何函数式接口、lambda 表达式或方法引用,实现断路器、限流、重试、舱壁隔离等弹性模式。
Resilience4j 的名称来源于 Resilience(弹性/韧性)+ 4j(for Java),寓意为 Java 应用提供弹性能力。
为什么需要 Resilience4j
在微服务架构中,服务之间存在大量的远程调用。当某个服务出现问题时,可能会导致:
- 级联故障:一个服务的故障导致调用方也出现故障,进而影响整个系统
- 资源耗尽:大量请求堆积,耗尽线程池、连接池等资源
- 雪崩效应:单点故障扩散到整个分布式系统
Resilience4j 提供的容错机制可以有效防止这些问题:
┌─────────────────────────────────────────────────────────────┐
│ 调用链路保护 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 请求 ─→ [限流] ─→ [舱壁] ─→ [熔断] ─→ [超时] ─→ [重试] ─→ 服务 │
│ │
│ 每一层都可以独立配置,组合使用 │
└─────────────────────────────────────────────────────────────┘
核心设计理念
- 轻量级:不依赖任何外部库,核心模块只依赖 Vavr(函数式库)
- 模块化:各功能独立成模块,按需引入,不强制绑定
- 函数式:基于装饰器模式,可装饰任何函数式接口
- 线程安全:所有模块都是线程安全的,可安全地在多线程环境使用
- 可组合:多个装饰器可以自由组合使用
核心模块
Resilience4j 提供以下核心模块:
| 模块 | 功能 | 适用场景 |
|---|---|---|
| CircuitBreaker | 熔断器 | 防止对故障服务的持续调用 |
| RateLimiter | 限流器 | 控制请求速率,保护系统不被压垮 |
| Retry | 重试 | 自动重试失败的操作 |
| Bulkhead | 舱壁隔离 | 限制并发调用数量,隔离故障 |
| TimeLimiter | 超时控制 | 限制操作执行时间 |
| Cache | 缓存 | 缓存函数调用结果 |
模块依赖关系
<!-- 核心库(必需) -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-core</artifactId>
</dependency>
<!-- 各功能模块(按需引入) -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-circuitbreaker</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-ratelimiter</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-retry</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-bulkhead</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-timelimiter</artifactId>
</dependency>
与 Hystrix 的区别
背景
Hystrix 是 Netflix 开源的熔断器库,曾是微服务容错的标准选择。但 Netflix 于 2018 年宣布 Hystrix 进入维护模式,不再开发新功能,官方推荐迁移到 Resilience4j。
详细对比
| 对比维度 | Hystrix | Resilience4j |
|---|---|---|
| 维护状态 | 停止维护(2018年) | 活跃开发中 |
| 设计理念 | 基于命令模式(HystrixCommand) | 基于装饰器模式(函数式) |
| 隔离策略 | 线程池隔离、信号量隔离 | 信号量隔离、线程池舱壁 |
| 依赖 | 依赖 Archaius、RxJava 等 | 仅依赖 Vavr |
| 配置方式 | 注解 + 配置文件 | 注解 + 配置文件 + 编程式 |
| Java 版本 | Java 6+ | Java 8+(函数式编程) |
| 响应式支持 | RxJava 1.x | RxJava 2/3、Reactor、Kotlin 协程 |
| Spring Boot | spring-cloud-starter-netflix-hystrix | resilience4j-spring-boot3 |
| 监控 | Hystrix Dashboard | Micrometer + Prometheus/Grafana |
| 学习曲线 | 较陡(概念多) | 较平缓(模块独立) |
迁移建议
// Hystrix 方式
@HystrixCommand(fallbackMethod = "fallback")
public String callService() {
return restTemplate.getForObject(url, String.class);
}
// Resilience4j 方式
@CircuitBreaker(name = "myService", fallbackMethod = "fallback")
public String callService() {
return restTemplate.getForObject(url, String.class);
}
为什么选择 Resilience4j
- 活跃维护:持续更新,支持最新技术栈
- 更轻量:无额外依赖,启动更快
- 更灵活:模块可独立使用,按需组合
- 更现代:支持 Java 8+ 函数式编程、响应式编程
- 更好的 Spring Boot 3 支持:官方提供 starter
快速开始
Maven 依赖
Spring Boot 3.x 项目(推荐)
<!-- Spring Cloud CircuitBreaker + Resilience4j(用于 Feign 集成) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<!-- Resilience4j Spring Boot 3 Starter(用于 @CircuitBreaker 等注解) -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
</dependency>
<!-- AOP 支持(注解生效必需) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
Spring Boot 2.x 项目
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>2.1.0</version>
</dependency>
4.2 基本使用
编程式使用
// 1. 创建熔断器
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofSeconds(10))
.slidingWindowSize(10)
.build();
CircuitBreakerRegistry registry = CircuitBreakerRegistry.of(config);
CircuitBreaker circuitBreaker = registry.circuitBreaker("myService");
// 2. 装饰函数
Supplier<String> decoratedSupplier = CircuitBreaker
.decorateSupplier(circuitBreaker, () -> backendService.call());
// 3. 执行
String result = Try.ofSupplier(decoratedSupplier)
.recover(throwable -> "fallback")
.get();
注解式使用(推荐)
@Service
public class MyService {
@CircuitBreaker(name = "myService", fallbackMethod = "fallback")
public String callBackend() {
return backendClient.call();
}
private String fallback(Throwable t) {
return "服务暂时不可用";
}
}
配置文件(application.yml)
resilience4j:
circuitbreaker:
instances:
myService:
sliding-window-size: 10
failure-rate-threshold: 50
wait-duration-in-open-state: 10s
CircuitBreaker 熔断器
工作原理
熔断器是 Resilience4j 最核心的模块,采用有限状态机实现:
┌─────────────────────────────────────────┐
│ 熔断器状态机 │
├─────────────────────────────────────────┤
│ │
│ 失败率 ≥ 阈值 │
│ ┌──────────────────┐ │
│ │ ▼ │
│ ┌──────┐ ┌──────┐ │
│ │CLOSED│ │ OPEN │ │
│ │ 关闭 │ │ 打开 │ │
│ └──────┘ └──────┘ │
│ ▲ │ │
│ │ 等待时间结束 │ │
│ │ ▼ │
│ │ ┌───────────────┐ │
│ │ │ HALF_OPEN │ │
│ │ │ 半开 │ │
│ │ └───────────────┘ │
│ │ │ │
│ │ 试探成功 │ 试探失败 │
│ └───────────┘──────────────→ OPEN │
│ │
└─────────────────────────────────────────┘
三种状态:
| 状态 | 说明 | 行为 |
|---|---|---|
| CLOSED | 关闭状态(正常) | 放行请求,统计失败率 |
| OPEN | 打开状态(熔断) | 快速失败,不调用后端 |
| HALF_OPEN | 半开状态(试探) | 放行部分请求试探后端 |
配置参数详解
resilience4j:
circuitbreaker:
configs:
default: # 默认配置
# ========== 滑动窗口配置 ==========
# 滑动窗口类型: COUNT_BASED(基于计数) 或 TIME_BASED(基于时间)
sliding-window-type: COUNT_BASED
# 滑动窗口大小
# COUNT_BASED: 最近 N 次调用
# TIME_BASED: 最近 N 秒的调用
sliding-window-size: 100
# 最小调用次数,达到此数才开始计算失败率
minimum-number-of-calls: 10
# ========== 熔断触发条件 ==========
# 失败率阈值(百分比),超过则打开熔断器
failure-rate-threshold: 50
# 慢调用率阈值(百分比),超过则打开熔断器
slow-call-rate-threshold: 100
# 慢调用时间阈值,超过此时间的调用被认为是慢调用
slow-call-duration-threshold: 60s
# ========== 熔断恢复配置 ==========
# 熔断器打开后等待时间,然后进入半开状态
wait-duration-in-open-state: 60s
# 半开状态允许的调用次数
permitted-number-of-calls-in-half-open-state: 10
# 是否自动从打开状态转换为半开状态
automatic-transition-from-open-to-half-open-enabled: true
# ========== 异常处理配置 ==========
# 记录为失败的异常类型(白名单)
record-exceptions:
- java.io.IOException
- java.util.concurrent.TimeoutException
- io.grpc.StatusRuntimeException
# 忽略的异常类型(不计入失败统计)
ignore-exceptions:
- com.example.BusinessException
# 记录失败的异常判断器(自定义)
# record-failure-predicate: com.example.MyPredicate
instances:
# 具体服务的熔断器配置
myService:
base-config: default # 继承默认配置
failure-rate-threshold: 60 # 覆盖部分配置
wait-duration-in-open-state: 30s
使用示例
注解方式
@Service
public class OrderService {
@CircuitBreaker(name = "inventoryService", fallbackMethod = "checkInventoryFallback")
public boolean checkInventory(Long productId) {
return inventoryClient.check(productId);
}
// fallback 方法:参数必须与原方法一致,最后可加 Throwable
private boolean checkInventoryFallback(Long productId, Throwable t) {
log.warn("库存服务不可用,productId: {}, 原因: {}", productId, t.getMessage());
return false; // 降级策略:默认无库存
}
}
编程方式
@Service
public class OrderService {
private final CircuitBreaker circuitBreaker;
public OrderService(CircuitBreakerRegistry registry) {
this.circuitBreaker = registry.circuitBreaker("inventoryService");
}
public boolean checkInventory(Long productId) {
return circuitBreaker.executeSupplier(() -> inventoryClient.check(productId));
}
}
监听熔断器事件
@Component
public class CircuitBreakerEventListener {
public CircuitBreakerEventListener(CircuitBreakerRegistry registry) {
CircuitBreaker circuitBreaker = registry.circuitBreaker("myService");
circuitBreaker.getEventPublisher()
.onStateTransition(event ->
log.info("熔断器状态变化: {} -> {}",
event.getStateTransition().getFromState(),
event.getStateTransition().getToState()))
.onFailureRateExceeded(event ->
log.warn("失败率超过阈值: {}%", event.getFailureRate()))
.onCallNotPermitted(event ->
log.warn("请求被熔断器拒绝"));
}
}
RateLimiter 限流器
工作原理
RateLimiter 用于控制请求速率,保护系统不被流量冲垮。Resilience4j 使用令牌桶算法实现:
┌─────────────────────────────────────────┐
│ 令牌桶算法 │
├─────────────────────────────────────────┤
│ │
│ ┌──────────────────────┐ │
│ │ 令牌桶(Token Bucket)│ │
│ │ 最大容量: 10 │ │
│ │ ┌─┬─┬─┬─┬─┐ │ │
│ │ │●│●│●│●│ │← 令牌 │ │
│ │ └─┴─┴─┴─┴─┘ │ │
│ └──────────────────────┘ │
│ ▲ │
│ │ 每周期补充 │
│ │ │
│ 请求 ──→ 获取令牌 ──→ 成功/等待/拒绝 │
│ │
└─────────────────────────────────────────┘
配置参数
resilience4j:
ratelimiter:
configs:
default:
# 限流周期
limit-refresh-period: 1s
# 每个周期允许的请求数
limit-for-period: 10
# 等待获取许可的超时时间
timeout-duration: 0s
instances:
myService:
base-config: default
limit-for-period: 100
使用示例
@Service
public class ApiService {
@RateLimiter(name = "myApi", fallbackMethod = "rateLimitFallback")
public String callApi() {
return externalApi.call();
}
private String rateLimitFallback(Throwable t) {
return "请求过于频繁,请稍后重试";
}
}
Retry 重试
工作原理
Retry 模块提供自动重试功能,适用于瞬时故障(如网络抖动):
┌─────────────────────────────────────────┐
│ 重试流程 │
├─────────────────────────────────────────┤
│ │
│ 请求 ─→ 调用 ─→ 失败? ─→ 重试次数内? ──→ 等待 ─→ 重调用
│ │ │ │
│ │ 成功 │ 超过次数 │
│ ▼ ▼ │
│ 返回结果 抛出异常 │
│ │
└─────────────────────────────────────────────────┘
配置参数
resilience4j:
retry:
configs:
default:
# 最大重试次数
max-attempts: 3
# 重试等待时间
wait-duration: 500ms
# 启用指数退避
enable-exponential-backoff: true
# 指数退避乘数
exponential-backoff-multiplier: 2
# 指数退避最大等待时间
exponential-max-wait-duration: 10s
# 需要重试的异常
retry-exceptions:
- java.io.IOException
- java.util.concurrent.TimeoutException
# 忽略的异常(不重试)
ignore-exceptions:
- com.example.BusinessException
instances:
myService:
base-config: default
max-attempts: 5
使用示例
@Service
public class PaymentService {
@Retry(name = "paymentRetry", fallbackMethod = "paymentFallback")
public PaymentResult pay(PaymentRequest request) {
return paymentGateway.process(request);
}
private PaymentResult paymentFallback(PaymentRequest request, Throwable t) {
log.error("支付失败,已重试多次: {}", t.getMessage());
return PaymentResult.failed("支付服务暂时不可用");
}
}
重试 vs 熔断
| 场景 | 重试 | 熔断 |
|---|---|---|
| 瞬时故障(网络抖动) | ✅ 适用 | ❌ 不适用 |
| 持续故障(服务宕机) | ❌ 会加重负载 | ✅ 适用 |
| 高延迟服务 | ❌ 会增加延迟 | ✅ 快速失败 |
最佳实践:重试 + 熔断组合使用
@CircuitBreaker(name = "myService")
@Retry(name = "myService")
public String callService() {
// 先重试,重试失败后触发熔断
}
Bulkhead 舱壁隔离
工作原理
Bulkhead(舱壁)借鉴了船舶设计理念——将船体分隔成多个舱室,一个舱室进水不会影响其他舱室。
在软件中,舱壁隔离限制并发调用数量,防止一个慢服务耗尽所有资源:
┌─────────────────────────────────────────┐
│ 舱壁隔离 │
├─────────────────────────────────────────┤
│ │
│ 服务A舱壁 服务B舱壁 │
│ ┌──────────┐ ┌──────────┐ │
│ │ 最大并发:10│ │ 最大并发:5 │ │
│ │ ████████ │ │ █████ │ │
│ │ 当前: 8 │ │ 当前: 5 │ │
│ └──────────┘ └──────────┘ │
│ │
│ 服务A故障不会影响服务B的资源 │
└─────────────────────────────────────────┘
8.2 两种实现
| 类型 | 实现方式 | 适用场景 |
|---|---|---|
| SemaphoreBulkhead | 信号量 | 同步调用,轻量级 |
| ThreadPoolBulkhead | 线程池 | 异步调用,完全隔离 |
配置参数
resilience4j:
bulkhead:
configs:
default:
# 最大并发调用数
max-concurrent-calls: 25
# 等待进入的最大时间
max-wait-duration: 0s
instances:
myService:
max-concurrent-calls: 10
thread-pool-bulkhead:
configs:
default:
# 核心线程数
core-thread-pool-size: 10
# 最大线程数
max-thread-pool-size: 20
# 队列容量
queue-capacity: 100
# 线程空闲时间
keep-alive-duration: 60s
使用示例
@Service
public class OrderService {
@Bulkhead(name = "orderBulkhead", fallbackMethod = "bulkheadFallback")
public Order createOrder(OrderRequest request) {
return orderProcessor.process(request);
}
private Order bulkheadFallback(OrderRequest request, Throwable t) {
log.warn("系统繁忙,请稍后重试");
throw new ServiceBusyException("订单服务繁忙");
}
}
TimeLimiter 超时控制
工作原理
TimeLimiter 用于限制异步操作的执行时间:
┌─────────────────────────────────────────┐
│ 超时控制 │
├─────────────────────────────────────────┤
│ │
│ 异步调用 ──→ 等待结果 │
│ │ │
│ ┌───────┴───────┐ │
│ │ │ │
│ 在超时内完成 超过超时时间 │
│ │ │ │
│ ▼ ▼ │
│ 返回结果 抛出 TimeoutException │
│ │
└─────────────────────────────────────────┘
重要说明
⚠️ TimeLimiter 只对异步方法生效(返回
CompletableFuture、Mono、Flux等)对于同步阻塞调用(如 gRPC BlockingStub),需要使用框架自带的超时机制。
配置参数
resilience4j:
timelimiter:
configs:
default:
# 超时时间
timeout-duration: 3s
# 超时后是否取消 Future
cancel-running-future: true
instances:
myService:
timeout-duration: 5s
使用示例
@Service
public class AsyncService {
@TimeLimiter(name = "myService", fallbackMethod = "timeoutFallback")
public CompletableFuture<String> asyncCall() {
return CompletableFuture.supplyAsync(() -> {
// 异步操作
return externalService.call();
});
}
private CompletableFuture<String> timeoutFallback(Throwable t) {
return CompletableFuture.completedFuture("操作超时,请稍后重试");
}
}
Spring Boot 集成
依赖配置
<!-- Spring Boot 3.x -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 如果需要 Feign 集成 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
启用 Feign 熔断
spring:
cloud:
openfeign:
circuitbreaker:
enabled: true
注解装饰器顺序
当多个注解组合使用时,执行顺序为:
Retry → CircuitBreaker → RateLimiter → TimeLimiter → Bulkhead → 实际方法
可通过配置修改顺序:
resilience4j:
# 装饰器执行顺序(从外到内)
# 数字越小越先执行
circuitbreaker:
circuit-breaker-aspect-order: 1
retry:
retry-aspect-order: 2
bulkhead:
bulkhead-aspect-order: 3
ratelimiter:
rate-limiter-aspect-order: 4
timelimiter:
time-limiter-aspect-order: 5
全局异常处理
推荐使用全局异常处理器统一处理 Resilience4j 的异常:
@RestControllerAdvice
public class Resilience4jExceptionHandler {
/**
* 熔断器打开时的异常
*/
@ExceptionHandler(CallNotPermittedException.class)
public Result<?> handleCircuitBreakerOpen(CallNotPermittedException ex) {
return Result.error("服务熔断中,请稍后重试");
}
/**
* 限流异常
*/
@ExceptionHandler(RequestNotPermitted.class)
public Result<?> handleRateLimiter(RequestNotPermitted ex) {
return Result.error("请求过于频繁,请稍后重试");
}
/**
* 舱壁满异常
*/
@ExceptionHandler(BulkheadFullException.class)
public Result<?> handleBulkheadFull(BulkheadFullException ex) {
return Result.error("系统繁忙,请稍后重试");
}
}
监控与可观测性
Actuator 端点
Resilience4j 与 Spring Boot Actuator 深度集成:
management:
endpoints:
web:
exposure:
include: health,circuitbreakers,ratelimiters,retries,bulkheads
endpoint:
health:
show-details: always
health:
circuitbreakers:
enabled: true
ratelimiters:
enabled: true
常用端点:
| 端点 | 说明 |
|---|---|
/actuator/circuitbreakers | 查看所有熔断器状态 |
/actuator/circuitbreakers/{name} | 查看指定熔断器详情 |
/actuator/circuitbreakerevents | 熔断器事件流 |
/actuator/ratelimiters | 查看所有限流器状态 |
/actuator/retries | 查看所有重试器状态 |
/actuator/bulkheads | 查看所有舱壁状态 |
Prometheus + Grafana
添加依赖:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
配置:
management:
endpoints:
web:
exposure:
include: prometheus,health
常用指标:
# 熔断器
resilience4j_circuitbreaker_state
resilience4j_circuitbreaker_calls_total
resilience4j_circuitbreaker_failure_rate
# 限流器
resilience4j_ratelimiter_available_permissions
resilience4j_ratelimiter_waiting_threads
# 重试
resilience4j_retry_calls_total
# 舱壁
resilience4j_bulkhead_available_concurrent_calls
最佳实践
配置建议
resilience4j:
circuitbreaker:
configs:
# 生产环境推荐配置
production:
sliding-window-type: COUNT_BASED
sliding-window-size: 100 # 统计最近100次调用
minimum-number-of-calls: 20 # 至少20次调用才计算失败率
failure-rate-threshold: 50 # 失败率50%触发熔断
wait-duration-in-open-state: 30s # 熔断30秒
permitted-number-of-calls-in-half-open-state: 10
# 测试环境配置(快速触发)
testing:
sliding-window-size: 4
minimum-number-of-calls: 2
failure-rate-threshold: 50
wait-duration-in-open-state: 10s
异常处理策略
-
业务异常不应触发熔断:
ignore-exceptions:
- com.example.BusinessException
- com.example.ValidationException -
只对网络/超时异常熔断:
record-exceptions:
- java.io.IOException
- java.util.concurrent.TimeoutException
- io.grpc.StatusRuntimeException
装饰器组合建议
// 推荐组合顺序
@Retry(name = "myService") // 1. 先重试
@CircuitBreaker(name = "myService") // 2. 重试失败后熔断
@RateLimiter(name = "myService") // 3. 限流保护
public String callService() {
return remoteService.call();
}
不同场景配置
| 场景 | 推荐配置 |
|---|---|
| 核心交易服务 | 高阈值(60-70%),短熔断时间(10-30s) |
| 非核心服务 | 低阈值(30-50%),长熔断时间(60s+) |
| 第三方服务 | 激进熔断 + 重试 + 超时控制 |
| 批量任务 | 宽松限流 + 长超时 |
常见问题
Q1: @CircuitBreaker 注解不生效?
检查清单:
- 是否添加了
spring-boot-starter-aop依赖 - 是否添加了
resilience4j-spring-boot3依赖 - 被注解的方法是否是
public - 是否通过 Spring 代理调用(不能是类内部调用)
- 配置文件中的实例名称是否与注解中的
name一致
Q2: fallback 方法不执行?
可能原因:
- fallback 方法签名不正确(参数必须与原方法一致,可选加
Throwable) - fallback 方法不是
private或同类中 - 异常被全局异常处理器先捕获了
推荐方案:使用全局异常处理器,不配置局部 fallback
Q3: TimeLimiter 对同步方法不生效?
原因:TimeLimiter 只对异步方法(CompletableFuture/Mono/Flux)生效
解决方案:
- gRPC:使用
withDeadlineAfter()设置超时 - HTTP:配置 RestTemplate/WebClient 超时
- Feign:配置 Feign 超时
Q4: 如何查看熔断器当前状态?
# 查看所有熔断器
curl http://localhost:8080/actuator/circuitbreakers
# 查看指定熔断器
curl http://localhost:8080/actuator/circuitbreakers/myService
Q5: 熔断器打开后多久恢复?
取决于 wait-duration-in-open-state 配置。等待时间过后,熔断器进入 HALF_OPEN 状态,允许试探性调用。如果试探成功,恢复到 CLOSED;如果失败,重新进入 OPEN。