2. Circuit Breaker 核心概念:Closed、Open、Half-Open 三种状态的定义与转换条件

Circuit Breaker(断路器)模式的核心是一个有限状态机,它通过 Closed(关闭)、Open(断开) 和 Half-Open(半开) 三种状态来管理对外部服务(或资源)的调用。状态机的设计目标是:在系统正常时最小化开销,在系统故障时快速熔断,并在系统恢复时自动探测。

2.1 三种状态的定义

状态 英文名称 定义 行为特征
关闭 Closed 断路器处于初始或正常状态,允许请求通过。 请求正常转发给下游服务;统计失败率;失败率未超阈值时保持此状态。
断开 Open 断路器因失败率超过阈值而跳闸,拒绝所有请求。 请求立即失败(快速失败),不调用下游;等待超时时间后进入半开状态。
半开 Half-Open 断路器在断开超时后进入的试探状态,允许有限数量的探测请求通过。 放行少量请求测试下游健康;成功则关闭,失败则重新断开。
关键理解: 三种状态形成了一个闭环的自我保护机制。Closed 是“信任”,Open 是“惩罚”,Half-Open 是“试探”。状态机的核心价值在于:防止级联故障 和 自动恢复。

2.2 状态转换条件与流程图

状态转换由三个核心参数驱动:失败阈值(如失败次数或失败率)、重置超时时间(从 Open 到 Half-Open 的等待时间)、探测请求数(Half-Open 状态下允许的最大请求数)。下图展示了完整的状态转换路径:

Circuit Breaker 状态机转换图 Closed 关闭状态 Open 断开状态 Half-Open 半开状态 失败率 ≥ 阈值 (如 50% / 10s) 超时时间到达 (如 30s) 探测请求成功 探测请求失败 说明:Closed → Open(失败触发);Open → Half-Open(超时触发);Half-Open → Closed/Open(探测结果触发)

2.3 状态转换条件详解

  1. Closed → Open:当在滑动时间窗口内(如 10 秒),请求失败率超过预设阈值(如 50%),或连续失败次数达到阈值(如 5 次),断路器从 Closed 跳转到 Open。此时所有后续请求立即失败,不再调用下游。
  2. Open → Half-Open:断路器在 Open 状态停留一段预设的 重置超时时间(如 30 秒)后,自动进入 Half-Open 状态。这是系统给下游服务的一个“恢复机会”。
  3. Half-Open → Closed:在 Half-Open 状态下,断路器允许有限数量的探测请求(如 3 个)通过。如果这些探测请求全部成功,则认为下游已恢复,断路器回到 Closed 状态,计数器重置。
  4. Half-Open → Open:在 Half-Open 状态下,如果任何一个探测请求失败,断路器立即回到 Open 状态,并重新开始计时重置超时时间。
常见陷阱: 不要将 Half-Open 状态视为“半恢复”状态。Half-Open 是一个高敏感度的试探状态,任何失败都会导致立即回到 Open。同时,Half-Open 状态下通过的请求数必须严格控制(通常为 1~3 个),否则可能在下游尚未完全恢复时造成二次冲击。

2.4 状态转换参数配置示例

在 Go 语言实现中,状态转换参数通常在初始化时配置。以下是一个典型的配置结构:

type CircuitBreakerConfig struct {
    // 失败阈值:滑动窗口内失败率达到此比例时触发 Open
    FailureRateThreshold float64 // 例如 0.5 (50%)

    // 滑动窗口大小:统计失败率的时间窗口(秒)
    SlidingWindowSize int // 例如 10

    // 最小请求数:滑动窗口内至少需要这么多请求才计算失败率
    MinRequestCount int // 例如 5

    // 重置超时:从 Open 到 Half-Open 的等待时间(秒)
    ResetTimeout time.Duration // 例如 30 * time.Second

    // 半开最大探测请求数:Half-Open 状态下允许的最大请求数
    HalfOpenMaxRequests int // 例如 3
}

2.5 状态转换的数学逻辑

状态转换可以用简单的伪代码逻辑表示:

// 每次请求完成后调用
func onRequestComplete(success bool) {
    switch state {
    case Closed:
        updateMetrics(success)
        if failureRate >= config.FailureRateThreshold &&
           totalRequests >= config.MinRequestCount {
            transitionTo(Open)
        }
    case Open:
        // 所有请求直接失败,不更新指标
        if timeSinceLastTransition >= config.ResetTimeout {
            transitionTo(HalfOpen)
        }
    case HalfOpen:
        if success {
            successfulProbes++
            if successfulProbes >= config.HalfOpenMaxRequests {
                resetMetrics()
                transitionTo(Closed)
            }
        } else {
            transitionTo(Open)
        }
    }
}
压测验证要点: 在压测中,需要重点验证以下边界条件:
• 失败率刚好达到阈值时是否准确触发 Open。
• 重置超时时间到达后是否准时进入 Half-Open。
• Half-Open 状态下探测请求成功/失败后的状态转换是否立即生效。
• 高并发场景下状态转换的原子性(避免竞态条件导致状态不一致)。

2.6 三种状态的行为对比

对比维度 Closed Open Half-Open
请求是否通过 是 否(快速失败) 有限通过(探测)
是否统计失败率 是 否 是(仅统计探测请求)
对下游的影响 正常调用 无调用(保护下游) 少量调用(试探)
触发下一状态的条件 失败率超阈值 超时时间到达 探测成功/失败
典型持续时间 不确定(正常时无限长) 固定超时(如 30s) 短(通常 1~3 个请求)