Resilience4j 入门:依赖引入、基本配置、创建熔断器实例
好,这一章咱们真正动手。Resilience4j 是什么?说白了就是一个轻量级的熔断限流库,专门给 Spring Boot 用的。我最早用 Hystrix,后来它停更了,就转到了 Resilience4j。嗯,感觉清爽很多——没有 Netflix 那一套厚重的依赖,配置也直接写在代码里,不搞什么注解魔法。
1. 依赖引入
先加 Maven 坐标。我用的是 Spring Boot 2.7.x + Resilience4j 1.7.1,注意版本适配,不然启动时会报 ClassNotFoundException。
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
如果你是 Gradle 项目,对应的写法是:
implementation 'io.github.resilience4j:resilience4j-spring-boot2:1.7.1'
implementation 'org.springframework.boot:spring-boot-starter-aop'
核心依赖就这两个。resilience4j-spring-boot2 会帮你自动装配 CircuitBreaker、RateLimiter、Retry 等组件,配合 @CircuitBreaker 注解开箱即用。starter-aop 是必须的,因为注解底层靠 AOP 拦截。
2. 基本配置
Resilience4j 支持两种配置方式:全局默认配置和实例独享配置。我个人习惯在 application.yml 里统一定义,再给关键调用单独覆盖。
下面是一个完整的配置模板:
resilience4j.circuitbreaker:
configs:
default:
sliding-window-size: 10 # 滑动窗口大小
minimum-number-of-calls: 5 # 最少调用次数(达到后才计算熔断)
failure-rate-threshold: 50 # 失败率阈值(%)
wait-duration-in-open-state: 5s # 进入 OPEN 后的等待时间
permitted-number-of-calls-in-half-open-state: 3 # HALF_OPEN 时允许的调用数
automatic-transition-from-open-to-half-open-enabled: true # 自动从 OPEN 转 HALF_OPEN
instances:
orderService:
base-config: default
failure-rate-threshold: 30 # 订单服务更敏感,失败率超过30%就熔断
paymentService:
base-config: default
wait-duration-in-open-state: 10s # 支付服务熔断后等久一点
每个参数什么意思?我整理了一张速查表:
| 配置项 | 默认值 | 说明 |
|---|---|---|
| sliding-window-size | 100 | 滑动窗口内记录的调用次数,窗口越大统计越准,但内存消耗也越大 |
| minimum-number-of-calls | 100 | 至少请求多少次后才开始计算失败率。我一般设小一点(5或10),方便测试 |
| failure-rate-threshold | 50 | 失败率达到多少百分比时熔断。线上建议 60-80,避免误伤 |
| wait-duration-in-open-state | 60s | 熔断打开后等待多少秒才尝试放行。我习惯设 5-10s,太长会影响恢复速度 |
| permitted-number-of-calls-in-half-open-state | 10 | 半开状态允许通过的测试请求数。设太少容易抖动,设太多又会压垮下游 |
| automatic-transition-from-open-to-half-open-enabled | true | 是否让熔断器自动从 OPEN 转为 HALF_OPEN。建议开启,不要手动干预 |
3. 创建熔断器实例
有了配置,就可以在代码里创建实例了。Resilience4j 提供两种用法:注解式和函数式。我先讲注解式,因为团队里大部分同事都用它,上手快。
在 Service 方法上加 @CircuitBreaker:
@Service
public class OrderService {
@CircuitBreaker(name = "orderService", fallbackMethod = "fallback")
public Order getOrder(Long orderId) {
// 调用远程服务或数据库
return restTemplate.getForObject("http://order-db/orders/" + orderId, Order.class);
}
public Order fallback(Long orderId, Throwable t) {
// 降级逻辑
log.warn("熔断触发了,orderId={}", orderId, t);
return Order.empty();
}
}
注意 fallback 方法的签名要和原方法一致,多一个 Throwable 参数。我曾经因为参数顺序写反,一直没触发 fallback,排查了一下午……嗯,记住原方法参数在前,Throwable 在最后。
如果你不想用注解,也可以用编程式创建 CircuitBreaker 实例:
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.slidingWindowSize(10)
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofSeconds(5))
.build();
CircuitBreakerRegistry registry = CircuitBreakerRegistry.of(config);
CircuitBreaker breaker = registry.circuitBreaker("orderService");
Supplier<Order> decorated = CircuitBreaker.decorateSupplier(breaker,
() -> restTemplate.getForObject("http://order-db/orders/{id}", Order.class, 1L));
Order result = Try.ofSupplier(decorated)
.recover(throwable -> Order.empty())
.get();
编程式更灵活,适合做单元测试或动态调整。不过平时我建议先注解式,出现问题再转编程式查细节。
来看一张熔断器的状态切换图,理解了这张图,所有配置就都串起来了:
4. 验证与调试
配置写完了,怎么确认它在工作?我的做法是写一个简单的 JUnit 测试,用 Mock 让远程调用一直抛异常,观察状态切换日志。
@SpringBootTest
class OrderServiceTest {
@Autowired
private OrderService orderService;
@Test
void testCircuitBreakerOpen() {
for (int i = 0; i < 20; i++) {
try {
orderService.getOrder(1L);
} catch (Exception ignored) {
}
}
// 检查熔断器状态
CircuitBreaker breaker = CircuitBreakerRegistry.ofDefaults()
.circuitBreaker("orderService");
assertThat(breaker.getState()).isEqualTo(CircuitBreaker.State.OPEN);
}
}
minimum-number-of-calls 设了 100,我只调了 10 次。把值改成 5 就正常了。另外记得在测试配置里关闭缓存,否则状态不会被更新。
另外,启动时加 --debug 可以看到 Resilience4j 的自动配置日志,确认你的实例名是否和配置里的匹配。名称不匹配会使用默认配置,有些坑就是在这里埋下的。
5. 一个小结
这一章我们不谈复杂场景,先把依赖、配置、实例创建这三步走通。你想想看,熔断器的核心其实就是一个状态机,配好滑动窗口大小和阈值,剩下的交给 Resilience4j 自动管理。我当年的第一个生产熔断配置就是随手写了个 50% 阈值,结果流量峰值时疯狂 OPEN/CLOSED 震荡,后来加了 minimum-number-of-calls 和合理的 wait-duration 才稳下来。嗯,先动手配一个试试,比什么都强。