3. 熔断器状态机:Closed、Open、Half-Open 及状态转换条件

熔断器(Circuit Breaker)是降级熔断作业的核心状态机。它通过三个有限状态——Closed(关闭)、Open(打开)、Half-Open(半开)——以及明确的转换条件,实现对下游依赖的自动保护与恢复。理解状态机是设计熔断策略的前提。

3.1 状态定义与行为对比

状态 含义 对请求的处理 对失败/超时的处理 典型触发条件
Closed 熔断器关闭,链路正常 正常转发请求到下游 累计失败计数/错误率 初始化或恢复后
Open 熔断器打开,链路切断 快速失败(返回降级响应) 不处理,直接降级 失败阈值达到
Half-Open 熔断器半开,试探恢复 允许有限探针请求通过 探针成功则关闭,失败则重新打开 Open 状态超时后
关键指标: 状态转换依赖三个核心参数——failureThreshold(失败阈值)、timeout(Open 状态等待时间)、probeCount(Half-Open 探针请求数)。生产环境中建议将 failureThreshold 设为 5-10,timeout 设为 30-60 秒。

3.2 状态转换条件详解

状态转换由事件驱动,每个转换都有明确的触发条件和副作用。以下按转换路径逐一说明:

  1. Closed → Open:当连续失败次数或滑动窗口内的错误率超过 failureThreshold 时触发。转换后立即启动 timeout 计时器,所有后续请求直接降级。
  2. Open → Half-Open:当 timeout 计时器到期时自动触发。转换后允许少量探针请求通过,其余请求仍降级。
  3. Half-Open → Closed:当探针请求全部成功(或成功率超过预设阈值)时触发。转换后重置失败计数,恢复正常流量。
  4. Half-Open → Open:当任意探针请求失败或超时时触发。转换后重置 timeout 计时器,重新进入 Open 状态。
避坑指南: 不要将 timeout 设置过短(如 < 10 秒),否则 Open 状态形同虚设,下游尚未恢复就进入 Half-Open,导致频繁震荡。建议 timeout 至少为下游平均恢复时间的 2-3 倍。

3.3 熔断器状态机流程图

下图展示了三个状态之间的完整转换路径,以及每个转换对应的触发条件。箭头上的标签即为转换事件。

熔断器状态机转换图 熔断器状态机转换图 Closed (关闭状态) Open (打开状态) Half-Open (半开状态) 失败阈值达到 超时到期 探针全部成功 探针失败 说明:箭头上的文字为转换条件。Closed→Open 由失败阈值触发;Open→Half-Open 由超时触发;Half-Open 根据探针结果决定回到 Closed 或 Open。

3.4 状态转换的代码实现示例

以下是一个简化的熔断器状态机核心逻辑,使用 Java 伪代码展示状态转换判断:

public class CircuitBreaker {
    private State state = State.CLOSED;
    private int failureCount = 0;
    private final int failureThreshold = 5;
    private final long timeoutMs = 30_000;
    private long lastFailureTime = 0;

    public boolean allowRequest() {
        switch (state) {
            case CLOSED:
                return true;
            case OPEN:
                if (System.currentTimeMillis() - lastFailureTime > timeoutMs) {
                    state = State.HALF_OPEN;
                    return true; // 允许探针
                }
                return false;
            case HALF_OPEN:
                return true; // 探针请求
            default:
                return false;
        }
    }

    public void recordFailure() {
        failureCount++;
        lastFailureTime = System.currentTimeMillis();
        if (state == State.HALF_OPEN) {
            state = State.OPEN; // 探针失败,回到 Open
        } else if (failureCount >= failureThreshold) {
            state = State.OPEN; // 达到阈值,打开熔断器
        }
    }

    public void recordSuccess() {
        if (state == State.HALF_OPEN) {
            state = State.CLOSED; // 探针成功,关闭熔断器
            failureCount = 0;
        }
    }
}
注意: 上述代码为单机示例。分布式环境下,熔断器状态需要跨进程同步(如通过 Redis 或 ZooKeeper),否则每个实例独立计数会导致熔断不一致。建议使用滑动窗口(如 10 秒内错误率)替代简单连续计数,以应对突发流量。

3.5 状态转换的典型时序

以下表格展示一个完整的熔断-恢复周期中各状态下的请求处理行为:

时间点 事件 当前状态 请求处理方式 失败计数
T0 系统启动 Closed 正常转发 0
T1 连续 5 次请求超时 Closed → Open 开始降级 5
T2 30 秒超时到期 Open → Half-Open 允许 1 个探针 5
T3 探针请求成功 Half-Open → Closed 恢复正常转发 0

若 T3 时刻探针失败,则状态回到 Open,并重新计时 30 秒。这种设计确保下游服务在恢复前不会承受大量请求冲击。