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 状态转换条件详解
状态转换由事件驱动,每个转换都有明确的触发条件和副作用。以下按转换路径逐一说明:
- Closed → Open:当连续失败次数或滑动窗口内的错误率超过
failureThreshold时触发。转换后立即启动timeout计时器,所有后续请求直接降级。 - Open → Half-Open:当
timeout计时器到期时自动触发。转换后允许少量探针请求通过,其余请求仍降级。 - Half-Open → Closed:当探针请求全部成功(或成功率超过预设阈值)时触发。转换后重置失败计数,恢复正常流量。
- Half-Open → Open:当任意探针请求失败或超时时触发。转换后重置
timeout计时器,重新进入 Open 状态。
避坑指南: 不要将
timeout 设置过短(如 < 10 秒),否则 Open 状态形同虚设,下游尚未恢复就进入 Half-Open,导致频繁震荡。建议 timeout 至少为下游平均恢复时间的 2-3 倍。
3.3 熔断器状态机流程图
下图展示了三个状态之间的完整转换路径,以及每个转换对应的触发条件。箭头上的标签即为转换事件。
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 秒。这种设计确保下游服务在恢复前不会承受大量请求冲击。