跳到主要内容

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。

详细对比

对比维度HystrixResilience4j
维护状态停止维护(2018年)活跃开发中
设计理念基于命令模式(HystrixCommand)基于装饰器模式(函数式)
隔离策略线程池隔离、信号量隔离信号量隔离、线程池舱壁
依赖依赖 Archaius、RxJava 等仅依赖 Vavr
配置方式注解 + 配置文件注解 + 配置文件 + 编程式
Java 版本Java 6+Java 8+(函数式编程)
响应式支持RxJava 1.xRxJava 2/3、Reactor、Kotlin 协程
Spring Bootspring-cloud-starter-netflix-hystrixresilience4j-spring-boot3
监控Hystrix DashboardMicrometer + 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

  1. 活跃维护:持续更新,支持最新技术栈
  2. 更轻量:无额外依赖,启动更快
  3. 更灵活:模块可独立使用,按需组合
  4. 更现代:支持 Java 8+ 函数式编程、响应式编程
  5. 更好的 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 只对异步方法生效(返回 CompletableFutureMonoFlux 等)

对于同步阻塞调用(如 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

异常处理策略

  1. 业务异常不应触发熔断

    ignore-exceptions:
    - com.example.BusinessException
    - com.example.ValidationException
  2. 只对网络/超时异常熔断

    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 注解不生效?

检查清单

  1. 是否添加了 spring-boot-starter-aop 依赖
  2. 是否添加了 resilience4j-spring-boot3 依赖
  3. 被注解的方法是否是 public
  4. 是否通过 Spring 代理调用(不能是类内部调用)
  5. 配置文件中的实例名称是否与注解中的 name 一致

Q2: fallback 方法不执行?

可能原因

  1. fallback 方法签名不正确(参数必须与原方法一致,可选加 Throwable
  2. fallback 方法不是 private 或同类中
  3. 异常被全局异常处理器先捕获了

推荐方案:使用全局异常处理器,不配置局部 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。


参考资料