第10章 熔断
第9章讲了微服务的全链路日志问题,本章就来谈谈所有微服务会遇到的第二个问题——熔断。
你可能有个疑问:熔断不是流量大时才会出现吗?其实不是的,这里存在一定误区。

10.1 业务场景:如何预防一个服务故障影响整个系统
在一个新零售架构系统中,有一个通用用户服务(很多页面都会使用),它包含两个接口。
问题一:请求慢
服务调用关系:User API → Basic Data Service → 3rd Location API
在 Basic Data Service 中,接口 /currentCarLocation 需要调用第三方系统的数据,但第三方响应速度很慢,而且有时还会发生故障。
问题表现:
- 用户反馈 App 整体运行速度慢到无法接受
- 通过 Thread Dump 发现 User API 的线程请求数接近极限值
- 所有线程都在访问第三方接口
- 因为连接数满了,其他页面不再受理 User API 的请求
问题二:流量洪峰缓存超时
服务调用关系:APP → User API → Basic Data Service → Redis/数据库
问题表现:
- 流量高峰时 Redis 中的通用权限列表超时
- 那一瞬间所有线程都需要去数据库读取数据
- 数据库 CPU 使用率升到 100%
- Basic Data Service 停止工作
- User API 所有线程都堵塞
- App 上的所有操作都不能使用
10.2 需要解决的问题
线程隔离
假设 User API 的最大连接数是 1000,每次调用 /currentCarLocation 时速度很慢:
- 可能 1000 个连接线程全部都在调用这个慢接口
- 希望控制
/currentCarLocation的调用请求数不超过 50 条 - 保证至少还有 950 条连接可用于处理常规请求
- 如果超过 50 条,设计备用逻辑进行处理
熔断
当数据库压力太大时:
- 发现近期某个接口的请求经常出现异常时,先不访问接口的服务
- 发现某个接口的请求总是超时时,先别访问它
10.3 Sentinel 和 Hystrix

| 特性 | Hystrix | Sentinel |
|---|---|---|
| 隔离策略 | 线程池隔离/信号量隔离 | 信号量隔离 |
| 熔断降级策略 | 基于失败比率 | 基于响应时间或失败比率 |
| 实时指标 | 滑动窗口 | 滑动窗口 |
| 规则配置 | 多种数据源 | 多种数据源 |
| 社区活跃度 | 停止开发新功能 | 活跃 |
最终选择 Hystrix 的原因:
- 满足需求
- 团队里有人用过 Hystrix,并通读了它的源代码
- 它是 Spring Cloud 默认自带的
10.4 Hystrix 的设计思路
10.4.1 线程隔离机制
当前服务与其他接口存在强依赖关系,且每个依赖都有一个隔离的线程池。
例如:
- 调用接口 A 时,并发线程的最大个数是 10
- 调用接口 M 时,并发线程的最大个数是 5
这样就不会出现一个慢接口把所有连接线程都卷入的问题。
两种隔离方式:
| 隔离方式 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 线程池 | 每个依赖接口维护一个线程池 | 可中断调用 | 切换线程资源损耗大 |
| 信号量 | 使用计数器控制并发数 | 切换快 | 接口开始调用就无法中断 |
10.4.2 熔断机制

1. 在哪种条件下会触发熔断
在一个滚动统计时间窗口中,若:
- 调用接口的总数量达到
circuitBreakerRequestVolumeThreshold - 超时或异常的调用次数与总调用次数之比超过
circuitBreakerErrorThresholdPercentage
就会触发熔断。
2. 熔断了会怎么样
在 circuitBreakerSleepWindowInMilliseconds 时间内,不再对外调用接口,而是直接调用本地的降级方法:
@HystrixCommand(fallbackMethod = "fallbackMethod")
public String callService() {
return restTemplate.getForObject(url, String.class);
}
public String fallbackMethod() {
return "服务暂时不可用,请稍后重试";
}
3. 熔断后怎么恢复
到达熔断休眠时间后:
- 放开对接口的限制(断路器状态为 HALF-OPEN)
- 尝试使用一个请求去调用接口
- 如果调用成功,恢复正常(状态为 CLOSED)
- 如果调用失败或超时,重新等待熔断休眠时间
10.4.3 滚动(滑动)时间窗口

假设时间窗口设置为 10 秒,numBuckets 设置为 10:
- 时间窗口划分为 10 小份,每份是 1 秒
- 每隔 1 秒都有一个时间窗口
- 1分0秒~1分10秒统计一次
- 1分1秒~1分11秒统计一次
- 以此类推...
在每个桶中,Hystrix 会统计:
- 成功数
- 失败数
- 超时数
- 拒绝数
10.4.4 Hystrix 调用接口的请求处理流程
成功流程:
- 发起请求
- 检查断路器状态
- 检查线程池/信号量
- 执行 HystrixCommand
- 计算健康状态
- 返回成功
失败流程:
- 发起请求
- 检查断路器状态(若熔断则直接降级)
- 检查线程池/信号量(若满则直接降级)
- 执行 HystrixCommand(若失败/超时则降级)
- 执行 Fallback 方法
- 返回降级结果
10.5 注意事项
10.5.1 数据一致性
假设服务 A 更新了数据库,在调用服务 B 时直接降级了:
- 服务 A 的数据库更新是否需要回滚?
- 服务 B 向服务 A 返回成功还是失败?
关于这个问题没有固定的设计标准,需要结合具体需求进行设计。
10.5.2 超时降级
服务 A 调用服务 B 时超时了:
- 服务 A 调用了降级方法
- 但服务 B 已经在执行工作并且没有中断
- 服务 B 处理成功后,会返回成功结果给服务 A
- 服务 A 已经使用了降级方法
- 导致服务 B 中的数据出现异常
10.5.3 用户体验
请求触发熔断后的 3 种情况:
| 情况 | 处理方式 |
|---|---|
| 读数据请求降级 | 在界面上给用户提示,或隐藏缺失的数据 |
| 写数据请求改为异步 | 根据实际情况判断是否给用户提示 |
| 写数据请求回滚 | 必须提示用户重新操作 |
10.5.4 熔断监控
熔断功能上线后只是完成了第一步:
- Hystrix 是事前配置的熔断框架
- 配置对不对、效果好不好,只有实际使用后才知道
- 需要从 Hystrix 的监控面板查看各个服务的熔断数据
- 根据实际情况再做调整
10.6 小结

解决的问题
引入 Hystrix 的项目方案一周就上线了,下面两个问题很快解决:
- 下游接口慢导致当前服务所有连接池的线程被占满
- 下游接口慢导致所有上游的接口雪崩
之后系统就没有再出现相关错误了。
Hystrix 的不足
Hystrix 的设计思想是事前配置熔断机制:
- 要事先预见流量情况、系统负载能力
- 预先配置好熔断机制
- 如果实际情况与预测不一样,预先配置好的机制达不到预期效果
所以项目上线后,项目组又根据监控情况调整了几次参数。
2018年后,Netflix 官方已不再为 Hystrix 开发新功能,转向开发 Resilience4j,对于 Hystrix 原有功能只做简单维护。
熔断和限流都是高并发场景中面试官最喜欢问的问题,接下来将讲解限流。