面试知识库
进阶

熔断器模式#

一句话答案#

熔断器三态:Closed→Open(错误率超阈值快速失败)→Half-Open(试探恢复),与限流区别:限流控速率,熔断防级联。

核心要点

与限流的区别: 限流控制请求速率,熔断在下游故障时快速失败

实现: Sentinel / Resilience4j / Hystrix(已弃用)

错误率怎么统计(深挖)#

面试官追问熔断,落点几乎都在「错误率到底怎么算出来的」和「三态转换的细节」。

滑动窗口统计错误率

熔断的触发依赖一个统计窗口,不能用「全局累计错误率」(会被历史数据污染、永远恢复不了),必须用滑动窗口只看最近一段时间:

  • Resilience4j:环形 bit buffer(RingBitSet)。窗口大小 N(比如 100 次调用),用一个环形位数组记录最近 N 次调用的成功/失败(1 bit 一次),新调用覆盖最老的一格,失败数靠增量维护——O(1) 计算最近 N 次的失败率。这是基于「次数」的滑动窗口(COUNT_BASED),也支持基于时间的(TIME_BASED)。
  • Sentinel:LeapArray 时间分桶。把一段时间(如 1 秒)切成若干个小桶(bucket),每个桶统计落在该时间片内的请求数/异常数/RT。统计「最近 1 秒错误率」时把覆盖窗口的几个桶累加。窗口随时间「跳跃前进」,过期的桶被复用清零——本质是时间维度的滑动窗口,避免了固定窗口跨界突刺问题。

最小请求数门槛(避免冷启动误判)

只看错误率会有「冷启动陷阱」:窗口里只有 1 次请求且失败,错误率就是 100%,会误触发熔断。所以必须设最小请求数阈值(Resilience4j minimumNumberOfCalls、Sentinel minRequestAmount):窗口内请求数没达到这个门槛时,不管错误率多高都不熔断。错误率统计要「样本量足够」才有意义。

三态转换细节(深挖)#

Closed ──错误率/慢调用比例超阈值且达到最小请求数──▶ Open
Open ──经过冷却等待窗口(如 5s)──▶ Half-Open
Half-Open ──探测请求成功率达标──▶ Closed(重置统计窗口)
Half-Open ──探测请求失败──▶ Open(重新进入冷却)
plaintext

Closed → Open:窗口内同时满足「请求数 ≥ 最小请求数」和「错误率/慢调用比例 ≥ 阈值」才跳闸,跳闸后所有请求直接快速失败(fail fast),不再真正调用下游。

Open → Half-Open:Open 不是永久的,等一个固定的「冷却等待窗口」后自动转 Half-Open,开始试探下游是否恢复。

Half-Open 并发探测控制:半开态不能放全部流量进去打下游,必须限制探测并发。Resilience4j 用 permittedNumberOfCallsInHalfOpenState 只允许放 N 个探测请求,多余的直接拒绝;统计这 N 个的成功率决定回 Closed 还是退回 Open。这是「逐步放量」的本质——先放几个试水,好了再全开。

状态切换的线程安全(CAS):高并发下多个线程可能同时发现「该跳闸了」,状态机用 CAS(AtomicReference compareAndSet) 保证状态转换是原子的、只有一个线程切换成功,避免重复初始化窗口或丢失状态。Resilience4j 的 CircuitBreakerStateMachine 就是 AtomicReference<CircuitBreakerState> + CAS 切换。

面试回答(2分钟版)

熔断器模式是微服务防止级联故障的关键设计模式,核心是一个三态状态机。Closed 状态下正常放行请求并持续统计错误率;当错误率超过设定阈值比如 50% 时切换到 Open 状态,此时所有请求直接快速失败返回兜底值,不再真正调用下游服务;经过一段冷却时间后进入 Half-Open 状态,放行少量探测请求测试下游是否恢复,成功则回到 Closed 恢复正常,失败则继续 Open。熔断和限流容易混淆但职责不同:限流是控制请求速率保护自己不被打垮,像门口排队控制入场人数;熔断是在下游故障时快速失败保护调用方,像发现下游着火了赶紧关门别让请求进去。两者协同工作——限流控入口,熔断控出口。实现框架方面 Hystrix 已停更,现在主流选 Sentinel 或 Resilience4j。Sentinel 支持慢调用比例、异常比例、异常数三种熔断策略,还能通过 Dashboard 动态调整阈值,比 Hystrix 的纯失败率触发更灵活。

追问与易错

追问方向:

  • “Sentinel 熔断策略有几种?”→ 三种:慢调用比例(RT 超阈值的请求比例过高)、异常比例(异常请求占比过高)、异常数(异常请求数超阈值);均可配置时间窗口和最小请求数
  • “熔断恢复后怎么逐步放量?”→ Half-Open 状态放行少量探测请求,若成功则关闭熔断恢复正常;若仍失败则重新打开熔断继续等待;Sentinel 支持配置 Half-Open 的探测请求数
  • “你用过熔断吗?什么场景?”→ 常见场景:调用第三方支付/短信等外部服务时加熔断,防止外部服务故障拖垮自身;微服务间非核心依赖(如推荐、评论)加熔断后降级返回兜底数据
  • “错误率到底怎么统计的?”→ 滑动窗口,不能用全局累计否则恢复不了。Resilience4j 用环形 bit buffer 记录最近 N 次成功/失败;Sentinel 用 LeapArray 把时间切成桶累加最近一段的异常数。必须配最小请求数门槛,样本太少不熔断,否则冷启动一次失败就 100% 误触发
  • “Half-Open 怎么避免探测请求把刚恢复的下游再打挂?”→ 限制半开态并发探测数(permittedNumberOfCallsInHalfOpenState),只放 N 个试探请求,多余的直接拒绝,按这 N 个的成功率决定回 Closed 还是退回 Open,实现逐步放量
  • “多线程同时触发状态切换会不会乱?”→ 状态机用 AtomicReference + CAS 保证转换原子,只有一个线程切换成功,避免重复重置窗口

易错点:

  • ❌ 熔断一直打开——有 Half-Open 恢复
  • ❌ 混淆熔断和限流的适用场景