Java

临时止血动作为什么也要记录回滚条件和观察指标?

很多止血动作不是做错了,而是做完以后没人说得清多久算有效、什么情况下撤回、先恢复哪一项。把动作目的、观察指标和回滚条件一起写下来,止血才不会从短期保护变成新的长期风险。

  • 故障排查
  • 止血动作
  • 回滚条件
  • 观测指标
  • 稳定性
12 分钟阅读

我见过最典型的一次“止血做对了,后面还是出事”,不是因为动作本身错了,而是因为没人把它当成一笔带期限的借款。

那次晚高峰,订单链路已经开始排队,值班同学很快做了三个动作:

  • 关闭同步重试
  • 暂停营销补偿任务
  • 对非核心活动入口限流

动作下去以后,曲线确实好看了不少:

  • timeout 降了
  • 线程池 queue 下来了
  • 连接池 pending 也开始回落

群里很快松了一口气,大家开始转去查根因。

真正的问题出在后面。

第二天上午,业务同学发现活动流量一直被压着,补偿任务也没恢复,部分订单状态延迟了半天。再往回看,现场其实没有谁能明确回答这三个问题:

  • 昨晚哪个动作算已经生效了?
  • 哪个动作只是暂时把错误率压下来,却把代价挪到了后面?
  • 现在该先恢复哪一项,恢复到什么程度算安全?

也就是说,止血不是没做,而是做完以后现场失忆了。

这也是我后来特别坚持的一件事:临时动作如果不同时写下观察指标和回滚条件,它就很容易从“保护系统”变成“给未来埋一个新的坑”。

那次事故里,最先缺的不是动作,而是动作的边界

很多人对止血动作的理解是“先把最危险的压力降下来”。

这当然没错。

但现场真正容易忽略的是,临时动作一旦下去,系统就进入了一个新的暂时状态。这个状态本身也要被管理。

比如:

  • 关重试,确实减轻了下游压力,但也可能放大用户显性失败。
  • 暂停补偿任务,确实给数据库和线程让了路,但会把业务积压留到后面。
  • 限流保住了核心链路,但损失面和投诉面会慢慢抬头。

所以动作做下去以后,现场至少还要继续盯三类东西:

  • 结果层:timeout、错误率、成功率是不是在往好走。
  • 资源层:线程、连接、排队、重试这些放大器是不是真的退了。
  • 代价层:限流损失、补偿积压、降级影响有没有在变重。

只盯总 RT,往往会把后两层全漏掉。

我后来更愿意把临时动作写成一张小卡片,而不是一句口头决定

那次事故以后,我们在群里开始要求每个止血动作都最少写四件事。

第一,动作要压的是哪段压力

不是只写“关重试”,而是写清:

  • 关的是哪一段同步重试
  • 目的是减哪个下游的叠加调用量
  • 预期先回落的是哪个资源指标

动作如果不带目的,后面就很难判断它是否真的打在了问题上。

第二,动作后先看哪几个指标

不是笼统地说“观察一下”,而是写死先看什么。

例如那次我们最后补记成:

  • 先看入口调用量和实际调用量倍率是否回落
  • 再看连接池 pending 和线程队列是否在 5 分钟内下降
  • 最后看 timeout 和 504 是否跟着回落

这三层顺序不能乱。

如果你只看外层 timeout 降没降,很可能会漏掉一个事实:动作只是把错误暴露方式换了,底层压力并没有真的退。

第三,什么情况下认定动作无效

这是很多现场最容易漏掉的。

动作下去以后,如果 5 分钟、10 分钟都没有出现预期中的资源回落,那就不能再把它当成“已经做了,所以先继续等”。

要提前说清:

  • 多久内看不到哪种变化,就算无效
  • 无效以后是继续加码、换动作,还是撤回

没有这一句,动作就会挂在那儿,既没人敢继续,也没人敢收回。

第四,什么时候开始撤,按什么顺序撤

这一步最像“麻烦事”,所以最容易被拖到最后。

但恰恰是它,决定临时动作会不会变成长期状态漂移。

像那次事故,如果当时先写清:

  • 连接池 pending 连续 15 分钟恢复到基线附近,才考虑恢复补偿任务
  • 先小流量恢复限流入口,再观察 10 分钟
  • 同步重试最后恢复,而且只能先恢复一层

第二天就不会出现“系统早稳了,但临时动作还半挂着”的情况。

回滚条件不是为了好看,而是为了防止第二轮波动

很多人会觉得,回滚条件等现场稳了再讨论也来得及。

我后来越来越不认同这个想法。

因为回滚本身也是一次动作,而且常常是一次新的扰动。

尤其下面几类动作,如果没有回滚条件,特别容易留下第二个问题:

  • 限流
  • 降级
  • 关闭重试
  • 暂停批任务或补偿任务
  • 回撤灰度

这些动作都不是“做了就完”。它们真正难的地方往往在于:

  • 什么叫已经稳了
  • 先恢复哪个,不先恢复哪个
  • 恢复过程中盯哪组指标防止二次抬头

不把这些提前写下来,现场一松劲,动作就会失去主人。

那次事故给我最深的教训,是“止血成功”和“现场结束”不是一回事

昨晚值班的时候,大家一看到 timeout 往下走,就很自然地觉得主要危机过去了。

可第二天回看才发现,真正的代价被留在了后面:

  • 被限流的入口少吃了一夜活动流量
  • 补偿任务积压把第二天上午的资源又顶了一波
  • 关掉的重试没有明确恢复窗口,应用行为和原始设计已经不一致

这说明止血成功最多只能证明一件事:事故扩散被暂时压住了。

它不等于:

  • 所有临时动作都可以无限期挂着
  • 业务代价可以不算
  • 系统已经回到了正常状态

这篇的边界在这里

如果你现在卡的是“超时风暴里到底先止血还是先定位”,更该先看接口超时风暴里,先止血还是先定位?如何判断分界线?

如果你还没把现场里的判断和动作按时间线记下来,也别直接跳到动作管理,先去看故障时间线怎么记,才能在 30 分钟后还原判断过程?

这篇只处理动作落地后的管理问题:怎么确保临时动作真的只是临时的。

所以后来我们在群里最怕看到的,不再是“先动一下”,而是“先动一下再说”

“先动一下”很多时候没有问题,现场本来就需要果断。

真正危险的是后半句:

  • 再说什么
  • 看什么再说
  • 多久后再说
  • 谁来决定再说

如果这些都没写,动作很快就会从应急手段,滑成一个没人负责的新常态。

止血动作真正成熟,不是因为团队敢动手,而是因为动手之前就知道:

它想压哪段压力,准备看什么来证明自己有效,又准备在什么条件下把自己撤回来。