Resilience4j入门
# Resilience4j 入门与实战
# 引言
构建高可用微服务的容错利器
在分布式系统中,故障是常态而非例外。如何优雅地处理服务调用失败、避免雪崩效应,是每个 Java 微服务开发者必须面对的问题。Resilience4j 作为轻量级、函数式、面向 Java 8+ 的容错库,正逐渐成为 Spring Cloud 生态中 Hystrix 的主流替代方案。本文将带你全面掌握 Resilience4j 的核心模块、使用方式及最佳实践。
📚 官方文档:https://resilience4j.readme.io/ 🧪 示例代码:https://github.com/resilience4j/resilience4j-spring-boot2-demo
# 为什么选择 Resilience4j?
在 Hystrix 宣布停止维护后,社区急需一个现代化的容错解决方案。Resilience4j 应运而生,其优势包括:
- 轻量无依赖:不强制依赖任何框架(如 Spring),可独立使用。
- 函数式编程风格:基于 Vavr(原 Javaslang)函数式库,支持 Lambda 表达式。
- 模块化设计:按需引入所需功能(熔断、限流、重试等),避免“大而全”。
- 与 Spring Boot 深度集成:通过
spring-boot-starter快速配置。 - 丰富的监控指标:天然支持 Micrometer,无缝对接 Prometheus + Grafana。
# Resilience4j 核心模块概览
Resilience4j 提供六大核心组件,可单独或组合使用:
| 模块 | 功能 |
|---|---|
| CircuitBreaker | 熔断器:快速失败,防止级联故障 |
| RateLimiter | 限流器:控制单位时间内的请求数 |
| Retry | 重试机制:对失败操作自动重试 |
| Bulkhead | 隔离舱:限制并发数,防止单个服务耗尽资源 |
| TimeLimiter | 超时控制:限制异步操作的最大等待时间 |
| Cache | 缓存:对结果进行缓存(较少使用) |
💡 实际项目中最常用的是前四项。
# 熔断器状态
在 Resilience4j 中,**熔断器(Circuit Breaker)**有三种核心状态,用于控制对外部服务的调用行为,防止故障蔓延。
这三种状态分别是:
# 1. 关闭状态(Closed / 状态值通常为 0)
- ✅ 正常工作状态。
- 所有请求都正常发送到下游服务。
- 熔断器会监控调用的成功与失败情况(例如:记录最近 N 次调用的失败率)。
- 触发条件:当失败率超过设定阈值(如
failure-rate-threshold: 50%)且满足最小请求数(minimum-number-of-calls),熔断器会跳转到“打开”状态。
📌 类比:电路正常通电,灯亮着。
# 2. 打开状态(Open / 状态值通常为 1)
- ❌ 熔断已触发,拒绝所有请求。
- 所有对该服务的调用立即失败,不会真正发出请求(避免加重下游负担)。
- 直接抛出
CallNotPermittedException(或执行 fallback 逻辑)。 - 目的:给下游服务“喘息时间”,防止雪崩。
- 自动恢复机制:经过一段预设时间(
wait-duration-in-open-state,如 10 秒)后,熔断器会自动进入“半开”状态,尝试恢复。
📌 类比:保险丝熔断,电路断开,灯灭了。
# 3. 半开状态(Half-Open / 状态值通常为 2)
- 🔍 试探性恢复状态。
- 允许有限数量的请求通过(由
permitted-number-of-calls-in-half-open-state控制,如 3 个)。 - 如果这些试探请求全部成功 → 熔断器回到“关闭”状态,恢复正常调用。
- 如果任一请求失败 → 熔断器重新回到“打开”状态,继续熔断。
📌 类比:轻轻合上电闸,看灯是否还烧保险丝——如果正常就彻底恢复供电,否则再次断开。
# 状态转换图
[失败率过高]
Closed ——————————→ Open
↑ |
| | [等待超时]
| ↓
└—————— Half-Open ←——————┘
↑ |
|成功 |失败
└──────┘
2
3
4
5
6
7
8
9
# 在 Resilience4j 中的状态值(用于监控)
当你集成 Micrometer + Prometheus 时,指标 resilience4j_circuitbreaker_state 会暴露以下数值:
| 状态 | 数值 |
|---|---|
| CLOSED | 0 |
| OPEN | 1 |
| HALF_OPEN | 2 |
例如:
resilience4j_circuitbreaker_state{name="userServiceCB"} == 1
表示 userServiceCB 熔断器当前处于打开状态,所有调用被拒绝。
# 小结
| 状态 | 是否放行请求 | 作用 |
|---|---|---|
| 关闭 | ✅ 是 | 正常调用,监控失败率 |
| 打开 | ❌ 否 | 快速失败,保护下游 |
| 半开 | ⚠️ 有限放行 | 试探服务是否恢复,决定是否闭合 |
# 快速上手:Spring Boot 集成 Resilience4j
# 1. 添加依赖(Maven)
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>2.2.0</version>
</dependency>
<!-- 可选:集成 Micrometer 监控 -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
2
3
4
5
6
7
8
9
10
11
注意:Spring Boot 3 用户应使用
resilience4j-spring-boot3。
# 2. 配置文件(application.yml)
resilience4j:
circuitbreaker:
instances:
userServiceCB:
failure-rate-threshold: 50 # 失败率阈值(%)
minimum-number-of-calls: 5 # 最小请求次数(才触发熔断判断)
wait-duration-in-open-state: 10s # 熔断开启后,等待多久进入半开状态
permitted-number-of-calls-in-half-open-state: 3 # 半开状态下,试探请求次数
sliding-window-size: 10 # 滑动窗口大小
sliding-window-type: COUNT_BASED # 基于计数(也可选 TIME_BASED)
ratelimiter:
instances:
userServiceRL:
limit-for-period: 10 # 每周期允许10次请求
limit-refresh-period: 1s # 周期为1秒
timeout-duration: 0 # 获取许可的等待超时(0表示立即失败)
retry:
instances:
userServiceRetry:
max-attempts: 3 # 最多重试3次
wait-duration: 100ms # 重试间隔
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 实战:四种核心模式代码示例
# 场景假设
调用用户服务 getUserById(id),需添加容错能力。
# 1. 熔断器(CircuitBreaker)
@Service
public class UserService {
@Autowired
private CircuitBreakerRegistry circuitBreakerRegistry;
public String getUserById(String id) {
CircuitBreaker cb = circuitBreakerRegistry.circuitBreaker("userServiceCB");
Supplier<String> decorated = CircuitBreaker
.decorateSupplier(cb, () -> externalCallToUserApi(id));
// 提供 fallback
return Try.ofSupplier(decorated)
.recover(throwable -> "Default User")
.get();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
使用
@CircuitBreaker(name = "userServiceCB", fallbackMethod = "fallback")注解更简洁(需启用 AOP)。
# 2. 限流器(RateLimiter)
public String getUserWithRateLimit(String id) {
RateLimiter rl = rateLimiterRegistry.rateLimiter("userServiceRL");
Supplier<String> decorated = RateLimiter
.decorateSupplier(rl, () -> externalCallToUserApi(id));
return Try.ofSupplier(decorated)
.recover(RequestNotPermitted.class, e -> "Too Many Requests!")
.get();
}
2
3
4
5
6
7
8
9
10
# 3. 重试(Retry)
public String getUserWithRetry(String id) {
Retry retry = retryRegistry.retry("userServiceRetry");
Supplier<String> decorated = Retry
.decorateSupplier(retry, () -> externalCallToUserApi(id));
return Try.ofSupplier(decorated)
.get(); // 自动重试,最终抛出异常或成功
}
2
3
4
5
6
7
8
9
# 4. 组合使用:熔断 + 重试 + 限流
public String getUserRobust(String id) {
CircuitBreaker cb = circuitBreakerRegistry.circuitBreaker("userServiceCB");
RateLimiter rl = rateLimiterRegistry.rateLimiter("userServiceRL");
Retry retry = retryRegistry.retry("userServiceRetry");
Supplier<String> supplier = () -> externalCallToUserApi(id);
Supplier<String> decorated = decorateSupplier(supplier, cb, rl, retry);
return Try.ofSupplier(decorated)
.recover(this::fallback)
.get();
}
private Supplier<String> decorateSupplier(Supplier<String> supplier,
CircuitBreaker cb,
RateLimiter rl,
Retry retry) {
return CircuitBreaker.decorateSupplier(cb,
RateLimiter.decorateSupplier(rl,
Retry.decorateSupplier(retry, supplier)));
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
⚠️ 注意装饰顺序:通常 限流 → 熔断 → 重试,但需根据业务调整。
# 注解驱动开发(推荐)
Resilience4j 支持通过注解简化代码:
@Service
public class UserService {
@Retry(name = "userServiceRetry", fallbackMethod = "fallback")
@RateLimiter(name = "userServiceRL")
@CircuitBreaker(name = "userServiceCB", fallbackMethod = "fallback")
public String getUserById(String id) {
return externalCallToUserApi(id);
}
private String fallback(String id, Exception ex) {
log.warn("Fallback for user: {}, error: {}", id, ex.getMessage());
return "Default User";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
需在启动类添加
@EnableAspectJAutoProxy并确保 AOP 生效。
# 监控与指标
Resilience4j 自动暴露 Micrometer 指标,例如:
resilience4j_circuitbreaker_state:熔断器状态(0=关闭,1=打开,2=半开)resilience4j_ratelimiter_available_permissions:剩余许可数resilience4j_retry_calls:重试次数统计
配合 Prometheus + Grafana,可构建实时容错看板。
# 最佳实践建议
- 合理设置熔断参数:避免过于敏感(频繁熔断)或迟钝(无法保护系统)。
- 重试需幂等:确保被调用接口支持重复请求。
- 限流与业务匹配:突发流量 vs 平稳流量,选择
TIME_BASED或COUNT_BASED。 - fallback 逻辑轻量:避免 fallback 本身成为瓶颈。
- 组合策略有顺序:通常先限流(入口控制),再熔断(故障隔离),最后重试(恢复尝试)。