熔断与降级
下游故障时,最差的做法是请求继续涌入然后集体超时。熔断快速失败,降级提供替代响应。面试必考熔断器三态和降级兜底。
熔断器三态
熔断器: 关闭 → 打开 → 半开 → 关闭
| 状态 | 行为 | 进入条件 |
|---|---|---|
| 关闭 | 正常调用,统计错误 | 错误率/慢调用率超阈值且达到最小请求数 |
| 打开 | 直接拒绝(快速失败) | 阈值触发 |
| 半开 | 放少量试探请求 | 打开后等待超时 |
关键参数:错误率阈值、最小请求数(请求太少统计无意义)、打开持续时间(多久试探一次)。熔断的价值:下游已故障时,快速失败比傻等超时好(不拖垮自己,给下游恢复时间)。
服务降级
降级是主动放弃次要能力保核心:
| 降级方式 | 做法 | 场景 |
|---|---|---|
| 默认值兜底 | 返回默认数据(空列表、默认配置) | 推荐列表挂了给热门兜底 |
| 缓存兜底 | 用旧缓存数据(见缓存设计篇逻辑过期) | 数据源故障 |
| 功能裁剪 | 关掉非核心功能(评论、个性化) | 流量高峰 |
| 异步降级 | 写操作转 MQ 异步处理 | 写链路过载 |
设计原则:先定优先级(核心链路保什么、可牺牲什么),降级开关要能动态控制(配置中心/开关平台),降级要有日志(知道降级了)。
熔断与降级的关系
- 熔断是手段:对下游故障的自动化保护(快速失败)
- 降级是策略:熔断/限流触发后,返回什么替代响应
- 组合:下游挂了 → 熔断打开 → 降级逻辑返回缓存/默认值 → 下游恢复 → 半开试探 → 熔断关闭
- 与限流的区别:限流保护自己(防输入过载),熔断保护下游和自己(防输出故障扩散)
实现与工具
- Java 生态:Resilience4j、Sentinel(含控制台)
- Python:pybreaker、tenacity(重试为主)
- 自研要点:三态机、滑动窗口统计、动态阈值配置、监控指标(熔断次数、降级比例)
面试追问
- 熔断器三态? 关闭(正常统计)、打开(快速失败)、半开(试探恢复)。错误率超阈值打开,超时后试探
- 熔断和限流的区别? 限流防输入过载(自己被打爆),熔断防输出故障扩散(下游挂了不傻等)
- 降级怎么设计? 先定优先级,核心保、次要弃;缓存/默认值兜底;开关动态控制;降级有日志
- 半开状态为什么必要? 直接关闭可能再次打爆刚恢复的下游,半开放少量试探请求验证健康
- 最小请求数为什么要有? 请求太少时错误率统计没意义(3 个请求 2 个失败就熔断太敏感)