熔断器三种状态详解:关闭、打开与半开

熔断器(Circuit Breaker)是微服务架构中实现弹性容错的核心模式。它通过三种状态——关闭(Closed)、打开(Open)和半开(Half-Open)——的自动转换,保护下游服务不被级联故障压垮。理解这三种状态的定义及其转换条件,是正确配置熔断器参数的前提。

3.1 状态定义与核心特征

下表从请求处理方式、健康指标和典型行为三个维度,对比三种状态的本质差异:

状态 请求处理方式 健康指标 典型行为
关闭(Closed) 正常转发请求到下游服务 统计失败率/超时率 持续监控,未达阈值
打开(Open) 直接拒绝请求(快速失败) 记录拒绝次数与等待时间 返回降级响应,不调用下游
半开(Half-Open) 允许有限数量的探测请求通过 评估探测请求的成功率 试探下游是否恢复

3.2 关闭状态(Closed)—— 正常运行的基线

定义:熔断器的初始状态,也是服务健康时的常态。在此状态下,所有请求都会正常转发给下游服务,熔断器内部维护一个滑动窗口计数器,持续记录请求的成功/失败情况。

转换条件:

  • 保持关闭:当失败率低于预设阈值(例如 50%)时,熔断器维持在关闭状态。
  • 触发打开:当滑动窗口内的失败率 达到或超过阈值,且请求量达到最小请求数(例如 10 次),熔断器立即从 Closed → Open。
关键参数:关闭状态主要受 failureRateThreshold(失败率阈值)和 slidingWindowSize(滑动窗口大小)控制。窗口大小决定了统计的灵敏度,窗口越小,对瞬时故障越敏感。

3.3 打开状态(Open)—— 快速失败的保护期

定义:熔断器触发后的保护状态。在此状态下,所有对下游的调用请求都会被立即拒绝,直接返回降级响应(如缓存数据、默认值或错误提示),避免下游服务因持续等待而耗尽资源。

转换条件:

  • 保持打开:熔断器内部维护一个计时器,在 waitDurationInOpenState(例如 30 秒)内,始终处于打开状态。
  • 进入半开:当等待时间 耗尽,熔断器自动从 Open → Half-Open,允许少量探测请求试探下游。
避坑提示:打开状态的持续时间不宜过短(< 5 秒),否则下游服务尚未恢复就再次涌入大量请求,导致“熔断抖动”;也不宜过长(> 120 秒),否则会过度降低系统可用性。建议根据下游服务的平均恢复时间(MTTR)来设定。

3.4 半开状态(Half-Open)—— 恢复试探的桥梁

定义:熔断器从打开状态恢复前的过渡状态。在此状态下,熔断器会允许有限数量的探测请求(例如 3 个)通过,去真实调用下游服务,并根据这些请求的结果决定下一步动作。

转换条件:

  • 恢复关闭:如果所有探测请求都成功(或成功率达标),熔断器认为下游已恢复,从 Half-Open → Closed,重置计数器,恢复正常流量。
  • 回到打开:如果任意一个探测请求失败(或超时),熔断器认为下游仍未恢复,立即从 Half-Open → Open,并重新开始等待计时。
核心参数:半开状态由 permittedNumberOfCallsInHalfOpenState(半开状态允许的调用次数)控制。该值不宜过大,否则可能在下游脆弱时造成二次冲击;也不宜过小(如 1 次),否则单次失败会导致误判。

3.5 状态转换流程图

下图完整展示了熔断器三种状态之间的转换路径与触发条件:

熔断器三种状态转换图 关闭状态 (Closed) 打开状态 (Open) 半开状态 (Half-Open) 失败率 ≥ 阈值 且请求量达标 等待时间耗尽 探测请求全部成功 → 恢复关闭 探测请求失败 → 回到打开 状态转换说明: • Closed → Open:滑动窗口内失败率超过阈值,熔断器触发保护。 • Open → Half-Open:等待指定时间后,熔断器自动进入试探阶段。 • Half-Open → Closed/Open:根据探测请求结果,决定恢复或继续熔断。

3.6 状态转换的时序与参数映射

为了更直观地理解参数如何影响状态转换,下面以 Resilience4j 的默认配置为例,展示一个完整的熔断周期:

// Resilience4j 熔断器配置示例(Java)
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)                    // 关闭状态:失败率阈值 50%
    .slidingWindowSize(10)                       // 关闭状态:滑动窗口大小 10 次
    .minimumNumberOfCalls(5)                     // 关闭状态:最小请求数 5 次
    .waitDurationInOpenState(Duration.ofSeconds(30))  // 打开状态:等待 30 秒
    .permittedNumberOfCallsInHalfOpenState(3)    // 半开状态:允许 3 次探测
    .build();

转换时序示例:

  1. 关闭状态:最近 10 次请求中有 6 次失败(失败率 60% > 50%),且总请求数 ≥ 5 → 触发打开。
  2. 打开状态:所有请求立即降级,持续 30 秒。30 秒后自动进入半开。
  3. 半开状态:允许 3 个探测请求通过。如果 3 次全部成功 → 恢复关闭;如果任意 1 次失败 → 回到打开,重新计时 30 秒。

3.7 三种状态的核心差异总结

对比维度 关闭状态 打开状态 半开状态
流量通过 全部通过 全部拒绝 仅限探测请求
下游压力 正常压力 零压力 极小压力
响应延迟 正常延迟 即时降级(毫秒级) 探测请求正常延迟
主要参数 failureRateThreshold
slidingWindowSize
waitDurationInOpenState permittedNumberOfCallsInHalfOpenState
典型场景 服务健康运行 下游故障或超载 下游恢复试探期
实践要点:半开状态是熔断器设计的精髓——它避免了“熔断后永久关闭”或“恢复后立即全量流量”两个极端。通过合理配置 permittedNumberOfCallsInHalfOpenState 和 waitDurationInOpenState,可以在保护下游和快速恢复之间取得平衡。