4、熔断器核心状态机详解:Closed、Open 与 Half-Open
熔断器的核心是一个三态状态机:Closed(关闭)、Open(打开) 和 Half-Open(半开)。这三个状态之间的转换逻辑直接决定了 API 熔断的灵敏度和恢复效率。本章将逐一拆解每个状态下的工作机制、关键参数与实现细节。
核心原则:熔断器在 Closed 状态下累积失败计数,达到阈值后跳转为 Open 状态直接拒绝请求,经过冷却时间后进入 Half-Open 状态发送试探请求,根据试探结果决定恢复为 Closed 或再次进入 Open。
4.1 Closed 状态:请求计数与阈值
Closed 是熔断器的初始状态,此时 API 网关正常转发所有请求。熔断器内部维护一个滑动窗口计数器,用于统计最近一个时间窗口内的请求成功/失败情况。
4.1.1 滑动窗口计数机制
滑动窗口将时间划分为多个小桶(bucket),每个桶记录该时间段内的请求结果。窗口随时间向前滑动,自动丢弃过期数据。
| 参数 | 典型值 | 说明 |
|---|---|---|
| 窗口大小 | 10 秒 | 统计最近 10 秒内的请求数据 |
| 桶数量 | 10 个 | 每个桶覆盖 1 秒,精度 1 秒 |
| 失败阈值 | 10 次 | 窗口内失败请求数达到此值触发熔断 |
| 最小请求数 | 20 次 | 窗口内总请求数低于此值时不触发熔断(防止低流量误判) |
| 失败率阈值 | 50% | 失败数 / 总请求数 ≥ 50% 时触发熔断(可选) |
最佳实践:建议同时使用绝对失败数阈值和失败率阈值。在低流量场景下,绝对失败数阈值起主导作用;在高流量场景下,失败率阈值能更快响应异常。
4.1.2 计数与阈值判断逻辑
每次请求完成时,熔断器执行以下判断流程:
- 记录结果:将请求结果(成功/失败/超时)写入当前时间桶。
- 聚合统计:计算滑动窗口内的总请求数、失败请求数、失败率。
- 前置检查:若总请求数 < 最小请求数,跳过熔断判断。
- 阈值比较:若失败数 ≥ 失败阈值 或 失败率 ≥ 失败率阈值,触发状态转换至 Open。
- 重置桶:若未触发熔断,继续累积下一个桶的数据。
// 伪代码:Closed 状态下的请求计数与阈值判断
class ClosedState {
slidingWindow: SlidingWindow
failureThreshold: int = 10
minRequestThreshold: int = 20
failureRateThreshold: float = 0.5
function onRequestComplete(result: RequestResult) {
// 1. 记录结果到当前时间桶
slidingWindow.record(result)
// 2. 聚合统计
totalRequests = slidingWindow.getTotalRequests()
failureCount = slidingWindow.getFailureCount()
failureRate = failureCount / totalRequests
// 3. 前置检查:低流量保护
if (totalRequests < minRequestThreshold) {
return // 不触发熔断
}
// 4. 阈值比较
if (failureCount >= failureThreshold ||
failureRate >= failureRateThreshold) {
transitionTo(State.OPEN)
}
}
}
4.2 Open 状态:快速失败
当熔断器进入 Open 状态后,所有发往该服务的请求将立即被拒绝,不再进行实际调用。这是熔断器保护下游服务最直接的手段。
4.2.1 快速失败机制
- 直接返回降级响应:网关拦截请求,返回预设的降级数据(如空列表、缓存数据、错误码 503)。
- 零网络开销:不建立 TCP 连接,不发送 HTTP 请求,避免占用连接池和线程资源。
- 冷却计时器:进入 Open 状态时启动冷却计时器,计时结束后自动转换至 Half-Open。
4.2.2 冷却时间配置
| 场景 | 推荐冷却时间 | 说明 |
|---|---|---|
| 瞬时故障(如网络抖动) | 5 ~ 15 秒 | 快速恢复,减少对用户的影响 |
| 服务过载(如 CPU 打满) | 30 ~ 60 秒 | 给服务足够的恢复时间 |
| 数据库故障 | 60 ~ 120 秒 | 数据库恢复通常需要更长时间 |
| 长时间熔断 | 指数退避(如 30s → 60s → 120s) | 防止频繁试探加重服务负担 |
注意:冷却时间不宜过短(< 3 秒),否则可能导致熔断器在 Open 和 Half-Open 之间频繁震荡,反而增加系统开销。建议最小冷却时间设为 5 秒。
4.3 Half-Open 状态:试探性恢复
Half-Open 是熔断器的恢复探测状态。在此状态下,熔断器允许有限数量的试探请求通过,用于验证下游服务是否已恢复正常。
4.3.1 试探请求策略
- 试探请求数:通常设置为 1 ~ 3 个并发请求,避免试探流量过大。
- 成功判定:所有试探请求成功 → 转换至 Closed,重置计数器。
- 失败判定:任意试探请求失败 → 立即回到 Open,重置冷却计时器。
- 超时处理:试探请求超时视为失败,防止慢调用影响判断。
4.3.2 试探请求的隔离性
试探请求应使用独立的超时配置和独立的连接池,避免与正常请求混用导致资源竞争。
| 参数 | 正常请求 | 试探请求 | 说明 |
|---|---|---|---|
| 超时时间 | 5000 ms | 2000 ms | 试探请求超时更短,快速判定 |
| 最大并发 | 200 | 1 | 试探请求严格控制并发数 |
| 重试策略 | 允许重试 2 次 | 不允许重试 | 试探请求一次失败即判定失败 |
4.4 状态转换参数配置清单
以下清单汇总了熔断器三个状态的核心配置参数,供 MRM 模型验证时参考:
| 状态 | 参数 | 推荐值范围 | 验证要点 |
|---|---|---|---|
| Closed | 滑动窗口大小 | 5 ~ 30 秒 | 窗口过小易误判,过大响应慢 |
| 失败阈值 | 5 ~ 20 次 | 根据服务正常失败率调整 | |
| 最小请求数 | 10 ~ 50 次 | 低流量保护,防止冷启动误熔断 | |
| 失败率阈值 | 40% ~ 60% | 与失败阈值配合使用 | |
| Open | 冷却时间 | 5 ~ 120 秒 | 根据故障类型动态调整 |
| 降级响应 | 缓存 / 默认值 / 错误码 | 降级数据必须可用且安全 | |
| Half-Open | 试探请求数 | 1 ~ 3 个 | 试探并发过高可能压垮恢复中的服务 |
| 试探超时 | 1000 ~ 3000 ms | 短于正常超时,快速判定 |
MRM 验证建议:在模型风险监控中,应定期检查熔断器的状态转换日志,重点关注 Closed → Open 的触发频率。如果触发频率过高(如每小时超过 5 次),说明阈值设置可能过于敏感,或下游服务存在持续性问题,需要调整参数或触发告警。