4. 熔断器的三种状态:Closed、Open、Half-Open

熔断器的状态机,说白了就是三个档位:关、开、半开。我最早接触熔断器的时候,觉得这不就是断路器么?通、断、试一下。后来在密钥服务上踩了坑才明白——这三个状态切换的时机和条件,才是真正决定系统鲁棒性的关键。

你想想看,密钥服务跟普通RPC调用不一样。它每次请求都涉及签名、验签、解密,一旦后端密钥服务器出现抖动,熔断策略如果太激进,正常流量也会被无辜拦在外面。如果太保守,熔断又形同虚设。嗯,这里我们得把三种状态掰开揉碎了讲清楚。

4.1 Closed 状态:熔断器闭合,请求正常通过

Closed 状态是熔断器的初始状态,也是日常稳态。在这个状态下,所有密钥请求都会正常发送到后端服务。熔断器只做一件事:统计失败率。

核心指标:熔断器内部维护一个滑动窗口(sliding window),记录最近 N 秒内的总请求数和失败数。当失败率超过预设阈值(比如 50%)时,熔断器就会从 Closed 跳转到 Open 状态。

我个人习惯把滑动窗口的粒度设在 10 秒,窗口内至少采样 20 个请求,才触发状态切换。为什么?因为如果请求量太少,一次超时就能把失败率拉到 100%,太容易误报。

参数 典型值 我的建议
窗口大小 10s 根据业务 QPS 调整,不低于 5s
失败率阈值 50% 密钥服务建议设 40% – 60%
最小请求数 20 防止冷启动误判

我在项目中遇到过一个问题:刚上线时,密钥服务器还在预热,前几秒的请求全部超时,熔断器直接 Open 了。后来我加了「最小请求数」门槛,低于 20 个请求不计算失败率,这才解决了误触。

4.2 Open 状态:熔断器断开,请求快速失败

一旦进入 Open 状态,熔断器会直接拒绝所有请求,立即返回错误或降级结果(比如返回缓存的密钥、走备用密钥服务)。这个状态会持续一段「休眠时间」(sleep window),通常是 5 到 60 秒。

注意:Open 状态下不能透传请求到后端。否则熔断就失去了保护意义。我见过一个线上事故,就是因为 Open 状态没完全拦截,导致后端被疯狂重试、直接打崩。

Open 状态的核心价值是「快速失败」。与其让所有请求都在超时中等待,不如立刻返回一个降级响应。对密钥服务来说,返回过期的临时密钥,总比让业务层阻塞到超时强。

我曾经在一个高并发签名服务里,把 Open 状态的休眠时间设成了 30 秒。结果发现 30 秒太长,业务方积压了大量请求,等熔断器 Half-Open 后集中放行,又把后端冲垮了。所以后来我改成动态休眠时间:根据失败率加权计算,失败率越高,休眠越长,但不超过 60 秒。

4.3 Half-Open 状态:熔断器半开,试探性放行

休眠时间结束,熔断器进入 Half-Open 状态。这时它只允许少量请求通过(比如 1 到 5 个),去真实调用后端服务。如果这些请求成功了,说明后端恢复了,熔断器就关闭(回到 Closed);如果失败了,则立即回到 Open,重新计时休眠。

为什么需要 Half-Open?说白了就是「探路」。你想想看,如果后端只闪断了一下,30 秒后就好了,你却永远不让他试,那服务就永远恢复不了。Half-Open 给了后端一个机会。

实践技巧:Half-Open 状态下通过的请求数不要超过 3 个。并且最好用独立的探针请求(不带业务冲销),避免因为试探影响了正常流量。我通常会在 Half-Open 时记录一个「恢复时间戳」,用于监控面板。

另外,Half-Open 状态的超时时间要设得比正常超时短一些。比如正常请求超时 5 秒,Half-Open 探针超时 2 秒。为什么?因为试探请求要快速拿到结果,如果 2 秒还没响应,基本也能判定后端还没恢复。

4.4 状态转换流程

把三个状态串起来,就是下面这张图。我每次画给团队看的时候,都强调那条从 Half-Open 回到 Open 的虚线——这往往是容易被忽略的反向路径。

熔断器三种状态转换图 熔断器状态转换图 Closed 关闭 / 正常通过 Open 断开 / 快速失败 Half-Open 半开 / 试探放行 失败率超阈值 休眠结束 试探成功 试探失败 虚线箭头:Half-Open 试探失败后立即回到 Open,重新计时

4.5 状态转换的触发条件对比

为了让你快速对比,我把三个状态的进入条件和退出条件整理成了一张表。

状态 进入条件 退出条件 典型持续时间
Closed 初始启动,或 Half-Open 试探成功 失败率超过阈值 无固定时长,不断监测
Open 失败率超阈值 休眠时间结束 5s – 60s(可配置)
Half-Open Open 状态休眠结束 试探请求全部成功 → Closed
任意试探失败 → Open
通常很短(1s – 5s)

总结一下:Closed 是默认通道,Open 是保护屏障,Half-Open 是康复测试。三个状态互相咬合,缺一不可。我个人习惯在代码里为每个状态增加一个计数器,方便定位到底是阈值不合理还是后端抖动。

4.6 避坑指南:状态切换的常见误区

  • 忘了 Half-Open 的超时设置:我刚开始用 Hystrix 时,没改 Half-Open 探针的超时,结果探针等了 5 秒才返回,这段时间其他请求还在排队,等于没试。后来我把探针超时设为 2 秒,并单独开一个线程池执行。
  • 状态转换没有考虑冷启动:密钥服务刚启动时,滑动窗口里全是失败,立刻 Open。解决方案就是前面说的「最小请求数」和「预热时间段」。
  • Open 状态下日志爆炸:每个拒绝的请求都打 error 日志,瞬间把磁盘打满。我推荐在 Open 状态第一秒打印一条「熔断已开启」的 warn 日志,后续每 10 秒聚合统计一次拒数量,而不是每条打。

嗯,这三种状态搞清楚了,熔断器就掌握了七八成。下一小段你需要理解的就是状态切换的元数据——滑动窗口的具体实现。不过那是独立的知识点,我们这会儿先消化掉眼前的流程。