4. CircuitBreaker 状态机详解:CLOSED、OPEN、HALF_OPEN 状态转换与滑动窗口原理
熔断器的核心是一个三态状态机,配合滑动窗口统计实现自动故障隔离与恢复。理解状态转换的触发条件和滑动窗口的数据结构,是调优熔断参数的前提。
4.1 三态状态机模型
CircuitBreaker 在 CLOSED(闭合)、OPEN(断开)、HALF_OPEN(半开) 三个状态间流转,每个状态对应不同的请求处理策略。
核心原则:CLOSED 状态正常转发请求;OPEN 状态快速失败;HALF_OPEN 状态试探性放行少量请求以验证服务是否恢复。
| 状态 | 含义 | 请求处理方式 | 进入条件 |
|---|---|---|---|
| CLOSED | 熔断器关闭,服务正常 | 正常转发请求,统计失败率 | 初始状态;或 HALF_OPEN 试探成功 |
| OPEN | 熔断器打开,服务被隔离 | 直接返回降级响应,不发起真实调用 | CLOSED 状态下失败率超过阈值 |
| HALF_OPEN | 熔断器半开,试探恢复 | 放行少量请求,观察成功率 | OPEN 状态等待超时后自动进入 |
4.2 状态转换流程与触发条件
状态转换由 失败率阈值、滑动窗口统计 和 等待时间 三个参数驱动。下图展示了完整的状态机流转路径:
4.3 滑动窗口原理与统计机制
滑动窗口是熔断器判断失败率的 数据基础。Resilience4j 支持两种窗口实现:基于计数 和 基于时间。
4.3.1 基于计数的滑动窗口
- 固定窗口大小(如 10 次调用),每次新请求入队,最旧请求出队。
- 窗口填满后才开始计算失败率,避免冷启动阶段误判。
- 适合调用频率稳定的场景。
4.3.2 基于时间的滑动窗口
- 将时间划分为多个桶(bucket),每个桶统计一个时间片的调用数据。
- 滑动窗口覆盖最近 N 个桶,滚动聚合失败率。
- 适合调用频率波动较大的场景,能更快响应突发故障。
| 特性 | 基于计数窗口 | 基于时间窗口 |
|---|---|---|
| 窗口定义 | 固定调用次数 | 固定时间长度 |
| 数据粒度 | 单次调用 | 时间桶(如 1 秒) |
| 内存开销 | 低(仅存储调用结果) | 中(需维护桶数组) |
| 适用场景 | 调用频率稳定 | 调用频率波动大 |
| 冷启动问题 | 窗口未满时不计算 | 首个时间桶数据稀疏 |
4.4 滑动窗口数据结构与计算过程
下图展示基于时间滑动窗口的内部结构,以 5 个桶、每个桶 2 秒为例:
调优建议:在 Spring Boot 中配置
resilience4j.circuitbreaker.configs.default.sliding-window-size=10 和 sliding-window-type=COUNT_BASED。对于高并发服务,推荐使用 TIME_BASED 并设置 minimum-number-of-calls=5 避免冷启动误熔断。
4.5 状态转换与滑动窗口的联动关系
滑动窗口为状态机提供 实时统计数据,状态机根据统计结果驱动转换:
- CLOSED 状态:每次调用完成后,将结果写入滑动窗口。窗口内失败率 ≥
failureRateThreshold且调用次数 ≥minimumNumberOfCalls时,状态切换为 OPEN。 - OPEN 状态:滑动窗口暂停写入,所有请求直接降级。计时器开始计算
waitDurationInOpenState。 - HALF_OPEN 状态:放行
permittedNumberOfCallsInHalfOpenState个请求,结果写入一个临时窗口。若全部成功则切回 CLOSED,否则切回 OPEN 并重置等待计时器。
常见误区:滑动窗口大小设置过小(如 3~5)会导致熔断器对瞬时抖动过于敏感,频繁误熔断。建议生产环境至少设置为 10~20,配合
slow-call-rate-threshold 慢调用率阈值一起使用。
4.6 关键参数速查表
| 参数名 | 默认值 | 作用 | 调优方向 |
|---|---|---|---|
sliding-window-size |
100 | 滑动窗口大小(次数或秒数) | 根据 QPS 调整,越大越平滑 |
sliding-window-type |
COUNT_BASED | 窗口类型:计数/时间 | 高并发用 TIME_BASED |
failure-rate-threshold |
50 | 失败率阈值(百分比) | 核心服务设 30,非核心可设 60 |
wait-duration-in-open-state |
60s | 熔断后等待恢复时间 | 根据故障恢复时长调整 |
permitted-number-of-calls-in-half-open-state |
10 | 半开状态试探请求数 | 不宜过大,避免压垮恢复中的服务 |
minimum-number-of-calls |
100 | 滑动窗口最小统计基数 | 防止冷启动误判 |
4.7 实战配置示例
以下是一个面向高并发订单服务的熔断器配置,使用基于时间的滑动窗口:
resilience4j.circuitbreaker:
configs:
default:
sliding-window-type: TIME_BASED
sliding-window-size: 10
minimum-number-of-calls: 5
failure-rate-threshold: 40
slow-call-rate-threshold: 50
slow-call-duration-threshold: 2000ms
wait-duration-in-open-state: 30s
permitted-number-of-calls-in-half-open-state: 3
instances:
orderService:
base-config: default
该配置中,滑动窗口覆盖最近 10 秒,至少统计 5 次调用后才计算失败率。失败率超过 40% 或慢调用率超过 50% 时触发熔断,等待 30 秒后进入半开状态,试探 3 个请求决定是否恢复。