入门: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 对比)。