Skip to content

入门:Opossum 与熔断器三态

基于 Opossum 8.x · 核于 2026-08

速查

  • Opossum 定义:Red Hat 维护的 Node.js 熔断器库nodeshift/opossum)。把可能失败的异步函数包进熔断器,用滑动窗口统计错误率,超阈值就跳闸(Open)让后续请求快速失败,防下游故障级联成雪崩。名字源于负鼠「遇险装死(plays dead)」——故障时快速失败不硬撑。
  • 为什么需要熔断器:微服务里 A 调 B、B 调 C。C 挂了 → B 的请求堆积(线程池/连接池耗尽)→ B 也挂 → A 也挂——雪崩。熔断器在 B 调 C 时介入:C 连续失败就「跳闸」,B 不再傻等 C,直接快速失败或走 fallback,B 自己活下来,阻断级联。
  • 熔断器三态(核心状态机):①Closed(闭合):正常状态,请求正常放行,同时统计错误率;②Open(打开):错误率超阈值,直接拒绝请求(快速失败或走 fallback),不再调下游,持续一个 resetTimeout 周期;③Half-Open(半开):resetTimeout 到期后放一个请求试探下游——成功则回 Closed(恢复),失败则回 Open(继续熔断)。
  • 错误率怎么算:错误率 = 失败次数 / 总调用次数,在滑动窗口(rollingCountTimeout,默认 10 秒)内统计,分桶(rollingCountBuckets,默认 10 桶 = 每秒一桶)。当错误率 > errorThresholdPercentage(默认 50%)调用量达 volumeThreshold(默认 0)时跳闸。
  • fallback(降级):熔断器 Open 或调用失败时执行的兜底函数——返回缓存数据、默认值、空结果、友好错误提示,保证业务「降级可用」而非硬崩。fallback 接收与原函数相同的参数。
  • 核心配置timeout(单次调用超时,默认 10s)、errorThresholdPercentage(错误率阈值,默认 50)、resetTimeout(熔断后多久试探,默认 30s)、rollingCountTimeout(统计窗口,默认 10s)、rollingCountBuckets(窗口分桶数,默认 10)、volumeThreshold(最小调用量才统计,默认 0)。
  • 事件机制:熔断器实例是 EventEmitter,发射 success/failure/reject/timeout/open/close/halfOpen/fallback/semaphoreLocked 等事件,用于日志、监控、告警。配合 opossum-prometheus 可导出 Prometheus 指标。
  • Node.js 事实标准:老牌的 circuit-breaker-js 自 2013 年后基本停更(12 年没更新),Opossum 是 Red Hat 维护、活跃更新的 Node.js 熔断器事实标准。
  • 进阶顺序熔断器原理详解容错模式与对比参考

一、为什么需要熔断器:从一次雪崩说起

微服务架构里,服务间互相调用是常态。没有保护时,一个下游故障会级联放大

用户 → 服务A → 服务B → 服务C(数据库/第三方API)

                      C 挂了(响应慢/超时)

没有熔断器:
  1. C 挂了,B 的请求都在等 C(超时 30s)
  2. B 的线程池/连接池被这些等待请求占满
  3. B 无法处理新请求(包括 A 调它的)→ B 也"挂了"
  4. A 的请求堆积 → A 也挂了
  5. 整个系统雪崩

有熔断器(B 调 C 时加熔断):
  1. C 连续失败 → B→C 的熔断器 Open
  2. B 调 C 时快速失败(毫秒级)或走 fallback,不再傻等
  3. B 的线程池不被占满 → B 继续服务其他请求(A 调它的能正常返回)
  4. 雪崩被阻断在 B 这一层

核心思想:故障不可免(网络抖、服务挂、DB 慢),但要把故障隔离在局部,不让它扩散成全局灾难。熔断器就是这个「隔离阀」。

二、熔断器三态:Closed、Open、Half-Open

熔断器是一个有限状态机,三个状态间的转换决定了它的行为:

                  错误率 > 阈值
        ┌──────────────────────────────┐
        ▼                              │
   ┌─────────┐                    ┌─────────┐
   │ Closed  │◄──── 试探成功 ─────│  Open   │
   │ (正常)  │                    │ (拒绝)  │
   └─────────┘                    └─────────┘
        ▲                              │
        │                              │ resetTimeout 到期
        │     ┌──────────────┐         │
        └─────│  Half-Open   │◄────────┘
   试探成功   │  (试探一个)  │   放一个请求试探
              └──────────────┘

                     │ 试探失败

              回到 Open(继续熔断)
  • Closed(闭合):正常工作状态。请求正常发给下游,熔断器在后台用滑动窗口统计错误率。当错误率超过 errorThresholdPercentage 且调用量达 volumeThreshold跳到 Open
  • Open(打开):熔断状态。所有请求直接快速失败(或走 fallback),不再调用下游——这是保护下游、释放上游资源的关键。持续一个 resetTimeout 周期(默认 30s)后,跳到 Half-Open。
  • Half-Open(半开):试探状态。放一个请求过去试探下游是否恢复——成功则回 Closed(恢复服务),失败则回 Open(继续熔断再等一个周期)。

三、错误率与滑动窗口

熔断器决定「是否跳闸」靠的是错误率,而错误率在滑动窗口内统计:

  • 错误率 = 窗口内失败次数 / 窗口内总调用次数。
  • 滑动窗口(rollingCountTimeout):默认 10 秒——只看最近 10 秒的数据,老数据滑出窗口不算。
  • 分桶(rollingCountBuckets):默认 10 桶,即 10 秒窗口分成 10 个 1 秒的桶,每秒一个桶滚动。这样错误率随时间平滑变化,不会因一个瞬时抖动永久跳闸。
  • volumeThreshold:最小调用量门槛。默认 0——但生产建议设个非零值(如 5),避免「调了 1 次失败 → 错误率 100% → 误跳闸」。
时间轴 →
窗口(10s):[桶0][桶1][桶2]...[桶9]   ← 当前窗口
            失败  失败  成功      成功
错误率 = 失败数 / 总数,超过 50%(默认)→ Open

四、fallback:降级保业务

熔断器 Open 或调用失败时,可以配置一个 fallback 函数兜底——返回缓存、默认值、空结果或友好错误,让业务「降级可用」:

javascript
const CircuitBreaker = require('opossum');

// 可能失败的异步函数(如调下游服务)
async function getUser(id) {
  const res = await fetch(`https://user-svc/${id}`);
  return res.json();
}

const options = {
  timeout: 3000,                    // 单次调用超时 3s
  errorThresholdPercentage: 50,     // 错误率 50% 跳闸
  resetTimeout: 30000,              // 30s 后试探恢复
};

const breaker = new CircuitBreaker(getUser, options);

// 设置 fallback:失败或熔断时返回兜底数据
breaker.fallback(() => ({ id: 0, name: 'guest', cached: true }));

breaker.fire(123)
  .then(console.log)        // 正常返回用户,或熔断时返回 {guest}
  .catch(console.error);     // 没有 fallback 时才会 reject
  • fallback 接收相同参数breaker.fallback((id) => ...) 的 id 和 breaker.fire(id) 一致。
  • fallback 也算失败:触发 fallback 时熔断器仍计为失败(继续统计错误率),直到 Closed 才恢复主路径。
  • fallback 设计:返回缓存(Redis/本地)、返回默认值(推荐列表用热门兜底)、返回空(列表返回 [])、返回友好错误(「服务暂不可用」)——取决于业务。

五、事件与可观测

熔断器实例继承 EventEmitter,发射丰富事件,是监控告警的基础:

事件触发时机
success调用成功
failure调用失败(业务异常/超时)
timeout调用超时
reject熔断器 Open/Half-Open 时拒绝请求
open状态从 Closed → Open(跳闸)
close状态从 Half-Open → Closed(恢复)
halfOpen状态从 Open → Half-Open(开始试探)
fallback触发了 fallback 函数
semaphoreLocked并发达上限(容量限制)被拒
javascript
breaker.on('open', () => alert(`熔断器打开:${breaker.name}`));
breaker.on('close', () => log('熔断器恢复'));
breaker.on('fallback', (result) => log('走了 fallback', result));

配合 opossum-prometheus 模块可导出 Prometheus 指标,接入 Grafana 做熔断监控大盘。

下一步

理解了熔断器三态与 Opossum 基础后,下一步深入熔断器原理详解(三态转换细节、错误率计算、Half-Open 试探、事件全清单),以及容错模式与对比(超时/重试/限流与熔断的组合拳、与 circuit-breaker-js 对比)。