接口超时风暴里,先止血还是先定位?如何判断分界线?
超时风暴最难的不是知不知道要止血或定位,而是没看清什么时候已经从“还可以取证”变成“再不减压就会整片扩散”。把影响面、资源水位、放大器和可逆动作放到同一条时间线上,分界线通常会比想象中清楚。
我见过最难做决定的一次超时风暴,不是在第一批 timeout 出来的时候,而是在第七分钟。
前六分钟里,大家都还能说服自己“再看两眼就能找到根因”。
第七分钟开始,情况突然变了:
submitOrder从单接口慢,扩到confirmOrder、lockCoupon一起超时。- 工作线程 queue 连续两分钟翻倍。
- 连接池 pending 从几十个涨到几百个。
- 上游重试把真实调用量顶到了入口流量的 2.4 倍。
值班群里随即分成两派。
一派说先止血,先关重试、先限流,不然系统要被拖穿。
另一派说先别乱动,SQL 还没看清,万一动作把证据打乱,后面更难查。
这类争论表面上是“止血还是定位谁更重要”,其实真正要判断的是另一件事:
现场到底还处在可以先取证的阶段,还是已经进入不先减压就会继续自我放大的阶段。
我后来越来越不把它理解成一个理念问题,而是一个时间窗口问题。
那次值班真正让我们换挡的,不是 timeout 数本身,而是放大器已经起来了
一开始大家盯的还是最显眼的现象:
- 用户报下单超时
- 网关 504 在涨
- 慢 SQL 条数变多
这些都重要,但它们还不足以决定“现在必须先止血”。
真正让决策换挡的,是下面几件事一起出现:
- 同一批请求开始被重试两次、三次。
- 排队时间增长速度明显快于真正业务处理时间。
- 某些实例上的线程和连接已经接近硬上限,但入口流量并没有继续涨太多。
- 明明根因还没完全确认,外层影响面却已经在自己扩大。
这时我们才意识到,现场已经不是“一个点慢了”,而是系统开始把这点慢放大成一片超时。
一旦走到这一步,继续只讨论根因,会越来越像在火势蔓延时继续研究第一簇火苗是怎么点着的。
我现在更愿意用四个问题来切这条分界线
不是抽象地问“止血重要还是定位重要”,而是连续问下面四件事。
第一,影响面是在收,还是还在扩
如果你看到的是:
- 还停留在单接口、少量实例、局部租户
- 波动范围没有继续外扩
- 其余核心接口仍然稳
那通常还说明证据窗口有价值,定位可以放前一点。
但如果你已经看到:
- 从一条接口扩到一串接口
- 从局部实例扩到整个服务
- 从少量超时扩到用户明显感知
那就别再把它当成“慢一点但还能继续看”的普通退化。
影响面如果还在扩,止血优先级通常就已经开始往前走了。
第二,资源水位是在抬一下,还是在逼近上限
我后来很少再只看 timeout 数本身,而是一定会一起看:
- 工作线程 active 和 queue
- 连接池 active 和 pending
- 重试量
- 网关 504
- 下游超时预算消耗
因为真正决定你还有多少操作空间的,不是用户已经抱怨多少,而是系统离“再多一点就整片卡死”还有多远。
那次事故里,SQL 其实还没完全查明,但线程和连接已经明显往硬上限顶。到了这个阶段,继续把主要精力放在细扣慢 SQL,就已经不是稳妥,而是拖延。
第三,放大器是不是已经接管了现场
很多根因本身没那么大,真正把事故打穿的是放大器。
典型放大器包括:
- 同步重试
- 批任务抢资源
- 半冷半热实例反复承压
- 调大 timeout 后请求占用更久
- 补偿任务把本来局部的问题抬成全局排队
如果这些东西已经同时出现,那就说明你面对的不再只是“根因”,而是“根因 + 系统自激”。
这时先减掉放大器,往往比先争论最底层哪条 SQL 最慢更重要。
第四,现在有没有低风险、可逆、能直接减压的动作
并不是每次都要上大动作。
那次最后先做的并不是重启、扩容、调大连接池,而是两件更克制的事:
- 先关高风险同步重试。
- 先暂停一批会打到同一库表的补偿任务。
原因很简单:
- 它们可逆。
- 它们减的是真正的放大量。
- 它们不会把现场一下打乱到完全失真。
这类动作一旦存在,止血就不再是“拍脑袋乱动”,而是有明确收益的优先步骤。
反过来,什么时候还可以先定位
也有一些现场,先止血反而会比先定位更危险。
比如:
- 只有单接口、少量样本异常,且没有明显扩散。
- 资源水位还比较低,系统远没到自激阶段。
- 当前唯一能做的动作是高风险大动作,比如大面积回滚、强制重启、整体扩容。
- 证据窗口很短,不先抓现场就会彻底丢失。
这时继续取证、先把最早分叉的证据抓住,往往更划算。
说到底,不是“定位总该先”或“止血总该先”,而是:
- 如果系统还没开始自己放大自己,定位窗口更值钱。
- 如果系统已经靠重试、排队、占用时间延长在自我加压,减压窗口更值钱。
那次事故里,真正起决定作用的是动作后的回落顺序
最后我们没有在群里继续争论,而是先关了同步重试,暂停了补偿任务,同时保留一组实例继续抓现场。
几分钟后最关键的不是“超时降了没有”,而是回落顺序:
- 重试量先掉下来。
- 工作线程 queue 随后回落。
- 连接池 pending 再跟着下降。
- 外层 504 和 timeout 才慢慢恢复。
这个顺序很重要。它证明现场当时真正更急的,不是继续深挖最底层 SQL,而是先把已经起来的放大器打掉。
等系统从自激边缘退回来,再去细看 SQL 和下游处理时间,定位空间反而更大。
也正是因为看到了这个回落顺序,我后来才更敢说:
超时风暴里的分界线,往往不在“你知不知道根因”,而在“系统是不是已经开始自己放大自己”。
这篇只讲切分界线,不替你决定具体动作清单
如果你现在已经明确要设计某个止血动作的观察指标、回滚条件和撤回顺序,更该继续看临时止血动作为什么也要记录回滚条件和观察指标?。
如果你现在还没分清 timeout 最早落在应用、网络还是下游依赖,也别在这里兜,直接去看接口超时增多时,先区分应用、网络还是下游依赖?。
这篇只处理一个现场判断:什么时候还能继续先找根因,什么时候必须先把放大链压住。
我后来最警惕的一句话,是“再看两分钟”
很多超时风暴真正失控,不是因为没人懂技术,而是因为所有人都觉得:
- 证据已经快够了
- 再看两分钟应该能定位
- 现在动手怕把现场打乱
结果这“两分钟”里,重试起来了,排队起来了,连接也被占满了。
等再想止血时,能选的动作已经越来越粗暴。
所以我现在更看重的,不是团队有没有背熟某套止血原则,而是有没有能力在第七分钟之前看出来:
系统现在是在等你定位,还是已经等不起了。