2. 熔断器状态机详解

熔断器的核心是一个三态有限状态机(Finite State Machine, FSM)。理解 Closed(关闭)、Open(打开) 和 Half-Open(半开) 之间的转换逻辑,是进行参数调优和故障演练的理论基础。任何偏离标准状态机的实现,都会导致熔断行为与预期不符。

2.1 三种状态的核心语义

状态 语义 对请求的处理 触发条件
Closed 正常运行态。熔断器认为系统健康,允许所有请求通过。 正常转发请求,并统计失败率或慢调用比例。 初始状态;或 Half-Open 状态探测成功后重置。
Open 熔断态。熔断器判定系统故障,立即拒绝请求。 直接返回降级响应(Fallback),不发起真实调用。 Closed 状态下,失败率/慢调用率超过阈值。
Half-Open 探测态。熔断器尝试放行少量请求,验证系统是否恢复。 允许有限数量的探测请求通过,其余请求仍被拒绝。 Open 状态持续达到预设的等待时间(sleepWindow)。
关键认知: 熔断器不是“熔断后永久关闭”,而是通过 Half-Open 状态实现自我修复。如果探测请求成功,系统自动恢复;如果失败,则重新进入 Open 状态,避免对下游造成二次冲击。

2.2 状态转换流程图

下图展示了标准熔断器状态机的完整转换路径,包含三个核心状态和四条转换边。

熔断器状态机转换图 熔断器三态状态机转换图 Closed (关闭态) Open (熔断态) Half-Open (半开态) 失败率/慢调用率超阈值 sleepWindow 超时 探测请求成功 探测请求失败 状态转换说明 • 绿色箭头:恢复路径 • 红色箭头:故障路径 • 灰色箭头:超时触发 初始状态

2.3 状态转换的详细机制

2.3.1 Closed → Open:熔断触发

在 Closed 状态下,熔断器维护一个滑动时间窗口(如 10 秒或 1 分钟),统计窗口内的请求总数和失败数。当满足以下条件时,状态切换为 Open:

  • 失败率阈值:例如失败率 ≥ 50%。
  • 慢调用阈值:例如响应时间超过 2 秒的请求占比 ≥ 30%。
  • 最小请求数:窗口内请求总数必须达到一个最小值(如 5 个),避免在低流量下误触发。
调优要点: 最小请求数(minimumNumberOfCalls)是防止“冷启动误判”的关键参数。在流量较低的测试环境,如果该值设置过大,熔断器可能永远不会触发;在生产环境,如果该值设置过小,单次抖动就可能触发熔断。

2.3.2 Open → Half-Open:等待与探测

进入 Open 状态后,熔断器启动一个计时器,计时时长由 sleepWindow(或 waitDurationInOpenState)参数控制。在计时器到期前,所有请求直接返回降级响应。计时器到期后,状态自动切换为 Half-Open。

  • sleepWindow 的作用:给下游系统一个“冷却”和“恢复”的时间窗口,避免熔断后立即重试导致雪崩。
  • 典型值:5 秒 ~ 60 秒,取决于下游恢复速度。

2.3.3 Half-Open → Closed 或 Open:探测结果判定

在 Half-Open 状态下,熔断器允许有限数量的探测请求通过(由 permittedNumberOfCallsInHalfOpenState 控制,通常为 1 或 2 个)。

  • 探测成功 → Closed:如果所有探测请求都成功,熔断器认为系统已恢复,重置计数器,回到正常状态。
  • 探测失败 → Open:如果任意一个探测请求失败,熔断器立即回到 Open 状态,并重新计时 sleepWindow。
避坑指南: 在 Half-Open 状态下,不要将 permittedNumberOfCallsInHalfOpenState 设置得过大。如果下游系统尚未完全恢复,大量探测请求涌入会再次压垮服务,导致“熔断-恢复-再熔断”的震荡现象。

2.4 状态转换的完整流程(含参数)

以下是一个基于 Resilience4j 的典型状态转换流程,展示了参数如何影响状态机行为:

// 配置示例(Resilience4j)
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)                    // 失败率阈值:50%
    .slowCallRateThreshold(30)                   // 慢调用率阈值:30%
    .slowCallDurationThreshold(Duration.ofSeconds(2)) // 慢调用定义:>2秒
    .minimumNumberOfCalls(5)                     // 最小请求数:5
    .slidingWindowSize(10)                       // 滑动窗口大小:10个请求
    .waitDurationInOpenState(Duration.ofSeconds(10)) // sleepWindow:10秒
    .permittedNumberOfCallsInHalfOpenState(2)    // 半开态允许探测数:2
    .build();

// 状态转换时序(伪代码)
// 1. Closed: 收到10个请求,其中6个失败 → 失败率60% > 50% → 切换到 Open
// 2. Open: 所有请求返回降级,等待10秒
// 3. Half-Open: 10秒后,允许2个探测请求通过
//    - 如果2个都成功 → 切换到 Closed
//    - 如果任意1个失败 → 切换到 Open,重新等待10秒

2.5 三种状态的对比总结

维度 Closed Open Half-Open
请求通过率 100% 0%(全部降级) 仅探测请求(通常 1~3 个)
统计窗口 滑动窗口(记录失败/慢调用) 无统计(直接拒绝) 仅统计探测请求结果
主要参数 failureRateThreshold, slidingWindowSize, minimumNumberOfCalls waitDurationInOpenState permittedNumberOfCallsInHalfOpenState
典型耗时 持续(直到触发阈值) 固定等待时间(如 10s) 短暂(探测完成即切换)
对下游影响 正常压力 零压力(完全隔离) 极小压力(探测请求)

2.6 状态机在分布式系统中的意义

熔断器状态机通过 Open 状态实现快速失败,保护调用方不被拖垮;通过 Half-Open 状态实现自动恢复,减少人工介入。这种设计在微服务架构中至关重要,尤其是在以下场景:

  • 级联故障预防:当下游服务 A 故障时,熔断器阻止上游服务 B 继续调用 A,避免 B 的线程池被耗尽,进而引发更广泛的雪崩。
  • 优雅降级:在 Open 状态下,调用方可以返回缓存数据、默认值或错误提示,保证核心业务流程可用。
  • 自适应恢复:Half-Open 状态允许系统在不确定下游是否恢复的情况下,以最小的代价进行探测,实现“无人值守”的自我修复。
实战建议: 在压测或混沌工程实验中,建议先单独验证状态机转换逻辑。例如,通过注入固定比例的失败请求,观察熔断器是否在预期时刻从 Closed 切换到 Open,并在 sleepWindow 到期后进入 Half-Open。这是后续参数调优的“冒烟测试”环节。