
一次下游服务变慢,往往不会只影响一个请求:等待中的线程、连接池和重试会继续堆积,最后把原本健康的调用方也拖垮。熔断器(Circuit Breaker)不是“请求失败就拒绝”的开关,而是一套让故障隔离、恢复探测和业务降级各归其位的状态机。
先明确:熔断器解决的是级联故障
超时负责给一次调用设上限,重试处理短暂抖动,限流控制入口流量;熔断器则在下游持续异常时,主动停止无意义的调用。它保护的是调用方有限的资源,也让依赖方有机会恢复。
| 机制 | 主要问题 | 典型动作 | 不应替代 |
|---|---|---|---|
| 超时 | 单次调用等待过久 | 到期取消或返回失败 | 健康检查 |
| 重试 | 偶发网络抖动 | 有限次数地再次请求 | 持续故障的补救 |
| 限流 | 入口超过容量 | 拒绝、排队或整形 | 下游故障隔离 |
| 熔断器 | 依赖持续失败或变慢 | 短路调用,执行降级 | 所有错误的掩盖 |
最常见的误用,是给每个失败请求都重试多次,同时没有总时限。这样故障期间的请求量会被放大。应该先设调用超时,再在幂等场景中做少量、带抖动的重试,最后由熔断器根据一段时间内的结果决定是否短路。
三个状态,不是三段 if

一个可推理的熔断器通常有以下状态:
- Closed(关闭):请求正常放行,并在滚动窗口记录总请求数、失败数和慢调用数。
- Open(打开):不再访问下游,立即返回定义好的降级结果;等待冷却时间结束。
- Half-Open(半开):只允许少量探测请求。探测成功达到门槛才关闭;任何失败都重新打开。
“失败”不能只看 HTTP 500。连接超时、连接池获取超时、业务约定的不可重试错误,都需要按语义分类。另一方面,客户端主动取消、参数校验失败等不反映依赖健康的结果,不应计入熔断统计。慢调用同样值得设阈值:即使最终成功,长时间占着连接也可能先引发雪崩。
1 | on result in Closed: |
这些数字不是通用答案。minimumRequests 要避免小样本误判;窗口应覆盖有代表性的流量;探测并发要足够小,不能刚恢复就再次压垮下游。把阈值和冷却时间放进可审计的配置,而不是散落在业务代码里。
降级结果必须符合业务承诺

短路后的返回值比“是否打开”更关键。读取推荐列表可以返回带时间戳的缓存,并明确标识为非实时;创建订单、扣款、发送指令等写操作则不应伪造成功。它们应返回可识别的“稍后重试”错误,或转交持久化队列,并用幂等键保证后续补偿不会重复执行。
给降级方案写下边界:数据最多可以旧多久?调用方可否重试?是否需要展示提示?谁负责补偿?若这些问题没有答案,熔断器只是把真实故障藏到了体验和数据一致性里。
让状态变化可观测、可演练
至少记录四类指标:状态转换次数、被短路的请求数、半开探测成功率,以及按依赖区分的失败/慢调用比例。状态从 Closed 到 Open 时应有带依赖名和阈值快照的结构化日志;告警则关注“打开持续多久”和“影响了多少关键请求”,避免只因一次瞬间转换就制造噪声。
最后,在预发或故障演练环境人为注入延迟、超时和错误率,检查三件事:调用方的并发是否回落,降级是否仍满足业务承诺,依赖恢复后是否能平滑回到 Closed。熔断器的价值不在于永不失败,而在于失败时让系统仍保持可控。