Java

值班时多个告警同时响,第一轮怎么把范围收清?

19:47,群里一下子进来 12 条告警:网关 502、下单超时、Redis 慢日志、CPU 高、Pod 重启。这个时候最值钱的动作,不是赶紧去认一个根因,而是先把告警墙压成几条清楚的故障线。

  • 故障排查
  • 告警处理
  • 值班
  • 稳定性
  • 方法论
16 分钟阅读

19:47,值班群一下子跳进来一排告警。

  • gateway 5xx 告警
  • order-service timeout 告警
  • Redis 慢日志
  • 两台应用实例 CPU 高
  • 一条 Kubernetes Pod 重启告警
  • 业务群开始说“下单页卡住了”

这种场景最容易把人拖进一种假忙:每条告警都像主线,每个人都能找到自己熟悉的一块先钻进去,十分钟后群里信息越来越多,但范围并没有变清楚。

那次现场里,我们前 8 分钟没有急着认根因,只做了一件事:把几屏告警压成几条故障线。

第一轮不是定位根因,而是把告警墙收成能讨论的形状

我当时在白板上只写了一个很土的表:

告警 / 现象最早时间影响面实例范围暂时归到哪条线
下单接口 timeout19:46用户下单受影响全量 API 暴露核心业务线
网关 50219:47用户可见全量暴露更像外层结果
Redis 慢日志19:45暂未知单分片明显共享资源线
2 台 Pod CPU 高19:44暂未知局部实例局部实例线
Pod 重启19:48暂未知单实例噪音待定

这个表的价值不在于“严谨”,而在于它逼着现场先回答几件最基本的事:

  • 哪些告警对应的是用户真实受损
  • 谁最早开始
  • 是全局问题,还是局部实例先冒出来
  • 哪些更像原因,哪些更像外层暴露

只要这几件事没答清,多告警现场就很容易查散。

我会先砍第一刀:到底是哪一类用户真的受影响了

多个告警一起响时,第一刀一定要砍影响面。

因为很多告警看起来都很吓人,但它们的重要性并不一样。

那次我先确认到的事实是:

  • 主要受影响的是“提交订单”这一条链路
  • 浏览商品、查库存、个人中心都还正常
  • 业务损害已经落在核心交易路径上

这一步一做完,有些告警的优先级自然就降下去了。

例如 Pod 重启这件事,当时看起来很显眼,但如果它只发生在一个边缘实例,而且和受损链路对不上,那它在第一轮就不该和“下单 timeout”抢主线。

我越来越相信,第一轮范围切分,不是找最红的告警,而是找最贴用户影响面的那条线。

第二刀看时间,不看颜色

线上多人协作时,最容易发生的一件事,是谁贴的图更红,大家就围过去。

但那次真正把现场收紧的,不是颜色,而是时间顺序:

时间事件
19:44两台 order-service Pod CPU 开始抬头
19:45Redis 某个分片开始出慢日志
19:46下单接口 timeout 开始抬
19:47网关 502 开始出现
19:48单个 Pod 被重启

这条时间线一摆出来,很多讨论自然就能停掉。

比如网关 502 看起来最贴用户,也最容易被拿来当“主故障”,但它显然是后出来的。它更像外层暴露,不太像第一现场。

同样,Pod 重启也在更后面,它更像后果或者伴随噪音,而不是第一轮最值得追的那条线。

多个告警一起响时,我特别想知道的不是“谁最严重”,而是:

谁最早开始和正常世界分叉。

第三刀看共享资源和局部实例,别把两个方向混成一锅

那次现场最容易让人乱的地方,是它同时出现了两种信号:

  • Redis 慢日志,像共享资源出问题
  • 两台 Pod CPU 高,像局部实例先坏

如果你不把这两条线分开,现场很容易卡在一句没法执行的话里:

“是不是 Redis 把应用拖慢了?还是应用自己有问题,把 Redis 打爆了?”

我当时的处理方式很简单:先不急着下结论,先把证据按“共享”还是“局部”摆开。

证据更像共享问题更像局部实例问题
Redis 慢日志集中在一个热点 key 分片
只有 2 台 Pod CPU 明显抬高
timeout 请求大多落在这 2 台 Pod
网关 502 是全局暴露可能是结果可能是结果

这样一拆,现场就不会再被一句“都有关系”拖着跑,而是能形成两条清楚的假设:

  1. 共享资源线:热点 key 或 Redis 等待是不是主因
  2. 局部实例线:为什么 timeout 和 CPU 高先集中在这 2 台 Pod

第四刀再看最近变更,但只拿它收敛,不拿它甩锅

那次 19:40 刚好还做过一次小流量路由调整,把华东一部分交易流量切到了新的网关分组。

这个信息一出来,很多人会立刻想把锅全压到变更上。我当时反而刻意压住了这个冲动。

最近变更当然要看,但我只用它来回答两个问题:

  • 它是不是解释了“为什么只有这 2 台 Pod 先吃到问题流量”
  • 它能不能和前面的时间线、影响面、实例范围闭起来

后来事实也确实如此:

  • 新网关分组把某类大请求更多地送到了这 2 台 Pod
  • 这批请求又刚好打到了 Redis 的热点 key
  • 于是局部实例先高 CPU、Redis 某个分片先慢、然后 timeout 和 502 才一起长出来

你看,最近变更很值钱,但它值钱的方式不是“谁改了谁背锅”,而是它帮现场把那条分叉线连上了。

切完这几刀以后,告警墙终于能收成三条线

前 8 分钟结束时,我们把一团乱麻收成了下面三条线:

线一:核心业务线

  • 用户下单超时
  • timeout 从 19:46 开始抬
  • 这是第一优先级,因为它直接对应用户损失

线二:共享资源线

  • Redis 某热点分片 19:45 开始慢
  • 需要有人确认是主因、放大器,还是被动结果

线三:局部实例线

  • 2 台 Pod 先高 CPU,且 timeout 样本更多落在它们身上
  • 需要确认是不是接到了不同流量,或者本地状态已经分叉

网关 502 和单 Pod 重启则暂时不单独拉主线,只当外层暴露和伴随症状处理。

这一步做完以后,分工才第一次有了意义:

  • 一个人盯用户影响和止血
  • 一个人顺着 Redis 热点 key 看共享资源
  • 一个人把那 2 台异常 Pod 拉出来做对照

如果这三条线没先切出来,后面的并行其实都是伪并行。

第一轮收范围时,我最怕这三种动作

一上来就按组件分工

“你查网关、我查 Redis、他查 Kubernetes。”

听上去很高效,实际上最容易把现场拆成三摊互相对不上的信息。

一上来就认一个总根因

多个告警一起响时,第一轮通常还不配说“根因”。

你能先把外层暴露、共享资源、局部实例、最近变更几条线收清,已经很值钱了。

一上来就把所有告警放在同一级

它们不是同一层东西。

有的是用户损害,有的是共享资源告警,有的是局部实例现象,有的只是后果。把它们平铺看,现场一定会散。

真到这种场景,我只想先做到一件事

不是“马上定位”,而是让现场从十几条碎线,收成几条能被验证、能被分工、能被舍弃的故障线。

只要第一轮能做到这一点,后面才谈得上是排查;不然再多人、再多图,也只是围着告警墙转圈。