熔断器的状态机是什么?Spring Cloud CircuitBreaker 如何工作?
简化版
熔断器用 CLOSED、OPEN、HALF_OPEN 状态阻止持续调用故障下游:关闭时统计失败或慢调用,超过阈值后打开并快速失败,等待后进入半开只放少量探测请求,再决定恢复或重新打开。Spring Cloud CircuitBreaker 提供统一抽象,现代项目常以 Resilience4j 作为实现,Hystrix 属于旧体系。
详细版
Resilience4j CircuitBreaker 基于计数或时间滑动窗口统计结果,只有达到最小调用数后才按失败率、慢调用率判断是否熔断。OPEN 期间请求不访问下游;等待时间到后进入 HALF_OPEN,允许有限探测,成功率满足条件才回 CLOSED。
熔断器不负责终止已经卡住的调用,必须配合网络超时或 TimeLimiter;Fallback 也不是必选空结果,而应根据业务返回缓存、排队、明确降级响应或继续失败。错误分类决定哪些异常计入失败,配置错误会把业务拒绝误判成系统故障。
完整版教学
一、为什么要熔断
下游变慢时,上游线程或连接持续等待,资源逐渐耗尽,故障会沿调用链扩散。熔断器在确认下游处于高失败状态后,暂时拒绝新调用,让请求快速失败并给下游恢复时间。
它保护的是调用方资源和整体系统,不是修复下游。打开期间仍应告警和定位根因。
| 机制 | 解决的问题 | 不解决的问题 |
|---|---|---|
| 超时 | 单次调用最多等多久 | 不能判断下游是否持续故障 |
| 熔断 | 持续失败时快速拒绝新请求 | 不能终止已经卡住的调用 |
| 降级 | 失败后返回什么业务结果 | 不能让错误结果变成真实成功 |
| 隔离 | 限制单个依赖占用资源 | 不能判断依赖是否恢复 |
记忆钩子:熔断器像电闸,发现某条线路持续异常就先断开保护整栋楼;它不是维修工,真正故障还要靠超时、告警和下游治理。
二、三态转换
CLOSED --失败率/慢调用率超阈值--> OPEN
OPEN --等待时间到------------> HALF_OPEN
HALF_OPEN --探测成功-----------> CLOSED
HALF_OPEN --探测失败-----------> OPEN
CLOSED 不是“永不失败”,只是正常放行并记录结果;HALF_OPEN 也不是恢复正常流量,而是受限探测,避免刚恢复的服务被瞬间压垮。
三、滑动窗口与阈值
计数窗口关注最近 N 次调用,时间窗口关注最近一段时间。最小调用数防止刚启动两次请求失败就按 100% 失败率熔断;失败率阈值和慢调用阈值则决定何时打开。
窗口太小容易抖动,太大又反应迟缓。参数应基于真实流量、错误基线和恢复时间压测,而不是所有接口共用一套数字。
计数窗口 size = 10
minimumNumberOfCalls = 5
failureRateThreshold = 50%
前 4 次:失败 4 次,但未达到最小调用数,不计算熔断
前 10 次:失败 6 次,失败率 60%,超过阈值 -> OPEN
慢调用率也类似。比如慢调用阈值是 2 秒,最近 20 次调用里有 12 次超过 2 秒,即使没有抛异常,也说明下游已经拖慢调用方资源,仍可能触发熔断。面试时要把“失败率”和“慢调用率”都说出来,才算完整。
四、Spring Cloud 的抽象层
业务可通过 CircuitBreakerFactory 创建命名熔断器,再包装 Supplier 或异步调用。Spring Cloud 提供统一接入与自动配置,Resilience4j 负责具体状态机、事件和指标。
不同实例名称应对应不同下游或关键接口,不能让一个低优先级接口的失败打开整个服务所有调用。配置层次还要确认默认组、实例配置和代码 Customizer 的优先关系。
五、哪些结果算失败
网络异常、超时和 5xx 通常应计入失败;参数错误、库存不足等可预期业务结果通常不该触发基础设施熔断。可通过异常记录与忽略规则分类,但前提是客户端先把响应转换成有语义的异常。
取消、Fallback 异常和超时包装异常也要观察实际类型。只按异常类名配置而不看调用链,容易导致指标与预期不符。
六、Fallback 的设计
商品详情可降级为缓存数据,推荐服务可返回空推荐;扣款失败则不能伪造成功。降级结果应携带“数据可能陈旧”或明确错误语义,并监控触发次数。
Fallback 自身也必须轻量可靠,若它继续同步调用另一个故障服务,会形成新的级联链。必要时用隔离舱限制不同依赖的并发资源。
七、与 Hystrix 的版本边界
Hystrix 已停止活跃开发,是旧 Spring Cloud Netflix 的常见答案。现代 Spring Cloud 使用 CircuitBreaker 抽象对接 Resilience4j 等实现;维护旧系统时可解释 Hystrix 线程池/信号量隔离,但新题不应把它写成默认方案。
面试作答可以按三层收束:
- 先讲状态机和滑动窗口,说明为什么会从 CLOSED 到 OPEN;
- 再讲超时、隔离和 Fallback,说明熔断器需要和其他机制配合;
- 最后讲 Spring Cloud 当前答案,明确 Resilience4j 与 Hystrix 的版本边界。
八、常见误区与追问
- 误区:熔断器能让超时中的请求立刻停止。 熔断器主要控制新请求是否放行,已发出的阻塞调用仍要靠 HTTP 客户端超时、取消或 TimeLimiter 控制。
- 误区:OPEN 就表示服务永久不可用。 OPEN 是暂时拒绝,等待时间到后会进入 HALF_OPEN 放少量探测请求判断是否恢复。
- 追问:为什么需要 minimumNumberOfCalls? 样本太少时失败率没有统计意义,两次失败就 100% 熔断会导致系统抖动。
- 追问:Fallback 可以返回成功吗? 只有有业务语义的替代结果才可降级,扣款、下单这类关键写操作不能伪造成功。
- 误区:所有异常都应该计入失败率。 参数错误、权限拒绝、库存不足等业务结果通常不代表下游故障,要按异常类型和状态码分类。
- 追问:Spring Cloud 当前推荐怎么答? 答 Spring Cloud CircuitBreaker 抽象加 Resilience4j 实现,并说明 Hystrix 是旧 Netflix 体系。
九、加强记忆
熔断器是“统计失败 → 打开拒绝 → 半开探测 → 恢复或重开”的状态机。它必须配合超时,按业务正确分类失败,Fallback 不能伪造成功;当前 Spring Cloud 答 CircuitBreaker + Resilience4j,Hystrix 要注明旧版本边界。