触发条件二:慢调用比例
聊完错误比例,咱得说说另一个更常见的触发条件——慢调用比例。其实在实际生产里,很多故障不是接口直接报错,而是响应慢得像乌龟,最终拖垮整个系统。
我个人习惯把慢调用叫做"温水煮青蛙"。刚开始可能只有几个请求变慢,比例慢慢爬升,等你发现时,线程池满了,队列堆了,整个应用就僵住了。
为什么会这样?因为慢调用不释放线程资源。一个请求在等数据库、调下游,**线程就一直在那挂着**。一个两个还好,当慢调用比例超过阈值,熔断器就该跳闸了。
什么是"慢调用"
你得先定义什么叫"慢"。不是所有超过1秒的都叫慢,得看你业务场景。
- RPC 调用:比如 dubbo 接口,通常 RT 在 10ms 以内,超过 500ms 就算慢。
- HTTP 接口:对外提供的 REST 接口,100ms-300ms 算正常。突然飙到 2 秒,得熔断。
- 数据库查询:简单查询超过 200ms 就该报警。
- 磁盘 IO:写入延迟超过 500ms,明显不对劲。
所以,慢调用的门槛是业务定制的。我在项目里见过统一设 1000ms 作为慢调用阈值的,结果有些核心接口本身就 800ms,系统刚启动就触发熔断,哭笑不得。嗯,这里要注意:慢阈值不是死的,得按接口级别配置。
时间窗口与慢调用比例
慢调用比例的原理很好理解——在**一个滑动时间窗口内**,统计慢请求占所有请求的百分比。超过阈值就触发熔断。
先看几个核心参数:
| 参数 | 典型值 | 说明 |
|---|---|---|
| slowCallThreshold | 500ms | 超过这个时间的请求算慢调用 |
| slowCallRatioThreshold | 80% | 慢调用占比超过这个值就熔断 |
| statIntervalMs | 10000ms | 滑动窗口的时间长度 |
| minRequestAmount | 5 | 最少请求数,避免极小样本触发 |
你想想看,如果窗口设 10 秒,阈值 80%。10 秒里进来 100 个请求,其中 85 个响应时间超过了 500ms,那慢调用比例就是 85% > 80%,熔断器打开。就这么简单。
最小请求数:很重要的防御机制
这里有个容易踩的坑。假设服务刚上线,流量还没起来。10 秒窗口里只来了 1 个请求,碰巧它很慢。按照比例算,1/1=100%,超过 80% 了,要熔断?
那显然不合理。所以有了 minRequestAmount 这个参数(默认 5)。只有窗口内请求总数 >= 这个值,才计算慢调用比例。小于它,不触发熔断。
我曾经见过生产环境把 minRequestAmount 设成 1 的。流量低峰期,一个慢请求就把整个链路熔断了。排查了半天,发现是配置不合理。这个参数就是保护你免受"偶然慢调用"的伤害。
滑动窗口的计算机制
说白了这个比例不是一次性算的。滑动窗口把时间切成很多小桶(bucket),每个桶统计一段时间内的成功、失败、慢调用次数。窗口不停滑动,新桶进来,旧桶出去。
假设窗口 10 秒,分成 10 个桶,每个桶 1 秒。那这 10 秒里的慢调用比例 = 所有桶的慢调用数之和 / 所有桶的总请求数之和。
我最早接触熔断是在一个电商大促项目。当时用的基于滑动窗口的实现。有一次排查线上问题,花了整整一个下午,才发现是因为某个桶的统计时间戳不同步,导致比例忽高忽低。嗯,后来统一改成**原子变量**维护窗口内总数,问题才解决。
下面这个流程图帮你理清慢调用比例触发的整个决策逻辑:
实战中的慢调用阈值设置
阈值设多少?不同场景不同。我根据经验整理了几类常见服务的参考值:
| 服务类型 | 慢调用阈值 | 比例阈值 | 窗口长度 | 说明 |
|---|---|---|---|---|
| 高频 RPC(dubbo/gRPC) | 100-200ms | 50% | 10s | 需要快速感知下游变慢 |
| 缓存操作(Redis/Memcached) | 50ms | 60% | 5s | 缓存通常很快,慢影响太大 |
| 数据库查询 | 500ms-1s | 70% | 15s | 慢查询有优化空间,不要一慢就熔断 |
| 第三方 API | 2-5s | 80% | 30s | 外部网络有波动,窗口留宽裕些 |
| 磁盘 IO / 文件操作 | 500ms | 60% | 10s | 磁盘问题不会短时间内恢复 |
一个具体的计数例子
说个真实的例子。有一次我处理一个支付网关的慢调用问题。配置如下:
- slowCallThreshold = 300ms
- slowCallRatioThreshold = 75%
- statIntervalMs = 10s
- minRequestAmount = 10
某天晚上 8 点,流量正常。窗口内的统计情况:
| 时间段 | 总请求数 | 慢调用数 | 慢调用比例 | 是否熔断 |
|---|---|---|---|---|
| 19:59:50 - 20:00:00 | 120 | 10 | 8.3% | 否 |
| 20:00:00 - 20:00:10 | 110 | 90 | 81.8% | 是(OPEN) |
| 20:00:10 - 20:00:20 | 105 | 95 | 90.5% | 是(OPEN) |
| 20:00:20 - 20:00:30 | 100 | 5 | 5% | 否(恢复) |
可以看到,20:00:00 那个窗口,比例 81.8% > 75%,触发了熔断。后续窗口持续熔断,直到 20:00:20 那个窗口慢调用数骤降,比例降到 5%,熔断器自动关闭。
这个例子说明什么?只要后一个窗口内慢调用比例低于阈值,熔断就能自己恢复。不用人工干预,这就是滑动窗口的美妙之处。
避坑指南
最后说几个我踩过的坑:
- 窗口设得太短:比如 1 秒。一个突发慢请求直接把比例推到 100%,导致频繁误熔断。窗口至少 5 秒起步。
- 所有接口用同一个阈值:我在项目中遇到过,用户查询接口 RT 本身就有波动,跟核心下单接口用同一阈值,结果用户接口频繁触发熔断。
- 忽略预热阶段:服务刚启动,JIT 还没生效,请求可能偏慢。前几分钟建议不参与慢调用统计,或者设高一些的 minRequestAmount。
- 只盯着比例不看值:比例高但请求量很小,也没太大危害。我通常加一个"慢请求数"的条件作为熔断保护的补充。
慢调用比例这个触发条件,说复杂不复杂,说简单也不简单。关键在于理解你的业务 RT 分布和滑动窗口的计算粒度。搞清楚了,熔断就不会乱跳,故障也不会漏掉。