触发条件二:慢调用比例

聊完错误比例,咱得说说另一个更常见的触发条件——慢调用比例。其实在实际生产里,很多故障不是接口直接报错,而是响应慢得像乌龟,最终拖垮整个系统。

我个人习惯把慢调用叫做"温水煮青蛙"。刚开始可能只有几个请求变慢,比例慢慢爬升,等你发现时,线程池满了,队列堆了,整个应用就僵住了。

为什么会这样?因为慢调用不释放线程资源。一个请求在等数据库、调下游,**线程就一直在那挂着**。一个两个还好,当慢调用比例超过阈值,熔断器就该跳闸了。

什么是"慢调用"

你得先定义什么叫"慢"。不是所有超过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,且比例 > slowCallRatioThreshold → 熔断。

我曾经见过生产环境把 minRequestAmount 设成 1 的。流量低峰期,一个慢请求就把整个链路熔断了。排查了半天,发现是配置不合理。这个参数就是保护你免受"偶然慢调用"的伤害。

滑动窗口的计算机制

说白了这个比例不是一次性算的。滑动窗口把时间切成很多小桶(bucket),每个桶统计一段时间内的成功、失败、慢调用次数。窗口不停滑动,新桶进来,旧桶出去。

假设窗口 10 秒,分成 10 个桶,每个桶 1 秒。那这 10 秒里的慢调用比例 = 所有桶的慢调用数之和 / 所有桶的总请求数之和。

我最早接触熔断是在一个电商大促项目。当时用的基于滑动窗口的实现。有一次排查线上问题,花了整整一个下午,才发现是因为某个桶的统计时间戳不同步,导致比例忽高忽低。嗯,后来统一改成**原子变量**维护窗口内总数,问题才解决。

下面这个流程图帮你理清慢调用比例触发的整个决策逻辑:

慢调用比例触发熔断决策流程 请求进入熔断器 窗口内请求总数 ≥ minRequestAmount? (默认 5) 否 不统计·正常放行 是 慢调用数 / 总请求数 ≥ slowCallRatioThreshold? (典型值 80%) 开启熔断(OPEN) 否 正常通过·继续统计 滑动窗口持续更新:新桶进入,旧桶淘汰 窗口内请求总数和慢调用数实时刷新 注意 慢调用比例计算依赖「滑动时间窗口」 窗口太短→毛刺多易误熔断;窗口太长→反应迟钝 建议根据业务 RT 波动周期调整,通常 10s - 30s

实战中的慢调用阈值设置

阈值设多少?不同场景不同。我根据经验整理了几类常见服务的参考值:

服务类型 慢调用阈值 比例阈值 窗口长度 说明
高频 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 磁盘问题不会短时间内恢复
特别注意:如果你的服务本身就有很长的慢 tail(比如 P99 800ms,P999 2s),设置慢调用阈值时要区分正常慢和异常慢。不要把正常的业务波动当成熔断信号。

一个具体的计数例子

说个真实的例子。有一次我处理一个支付网关的慢调用问题。配置如下:

  • 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。
  • 只盯着比例不看值:比例高但请求量很小,也没太大危害。我通常加一个"慢请求数"的条件作为熔断保护的补充。
我的建议:第一次配置慢调用比例时,先用监控模式采集 3-7 天数据,观察正常业务下的慢调用比例峰值,然后再确定 "slowCallRatioThreshold"。别拍脑袋设个 50% 就上线。

慢调用比例这个触发条件,说复杂不复杂,说简单也不简单。关键在于理解你的业务 RT 分布和滑动窗口的计算粒度。搞清楚了,熔断就不会乱跳,故障也不会漏掉。