Java

告警太多但诊断仍慢,问题常出在“没按故障链分层”

真正拖慢值班的,往往不是告警不够,而是 20 多条红点挤在同一层里。把告警按起点层、放大层、结果层重新整理,并绑定到第一轮动作上,团队才会从“看见很多异常”变成“顺着一条故障链往下收”。

  • 告警分层
  • 稳定性治理
  • 值班体系
  • 故障排查
  • Java
13 分钟阅读

有一次晚高峰,值班群里 6 分钟之内进了 23 条告警。

最刺眼的是网关 504。

第二刺眼的是订单接口超时。

再往下还有线程池队列、连接池 pending、数据库 RT、Redis 超时、消费堆积、命中率下降。

从“观测覆盖”这个角度看,这套监控很完整。可那天现场并没有因为告警齐全而更快,反而更慢。大家都在处理异常,但没有人敢说第一轮应该顺哪条线往下走。

事故后回放那 6 分钟时,我们发现真正有用的第一张图,根本不是告警墙,而是一条按时间摊开的变化顺序:

  • 21:17,promo-cache 的超时和 miss 一起抬头。
  • 21:18,promotion-service 连接池 pending 开始堆。
  • 21:19,订单应用工作线程占满,重试量上升。
  • 21:21,网关 504 和支付页超时全面冒头。

那次之后,团队才真正接受一件事:

告警多不等于诊断快。真正拖慢值班的,往往是所有告警都挤在一个平面上,看不出谁更接近起点,谁只是放大,谁只是最外层结果。

这篇文章不想再讲一套抽象的“告警治理原则”。我只想把那次事故逼出来的一条经验讲清:告警如果不按故障链分层,现场就只能追最红的那块屏。

我们当时不是缺告警,而是缺“先后感”

那天值班群里最常出现的三句话是:

  • “504 先看吧,用户已经能感知了。”
  • “数据库也红了,要不要先拉 DBA?”
  • “Redis 也在抖,到底谁是起点?”

这三句话都不算错。

错的是它们都把同一条故障链上的信号,当成了并列问题。

如果你把下面这些东西同时摆平:

  • 外层报错
  • 中间资源堆积
  • 最底层依赖波动

值班现场就会天然分裂成几拨人,各追各的红点。人越多,越容易形成一种错觉:大家都在干活,所以现场应该在收敛。其实只是把一条链拆成了几摊噪音。

后来复盘时最扎心的一句评价不是“告警漏了”,而是:

所有告警都对,但它们没有帮助值班同学判断先看哪一层。

后来我们怎么把同一批告警重新摆位置

事故结束后,我们没有先删告警,也没有先讨论阈值。

我们先做了一件很笨但很有用的事:把那次事故里所有触发过的告警按“它在故障链里所处的位置”重新贴墙。

贴完以后,才有了下面这三个层次。

第一层:起点层

这层不是“最严重”,而是最可能最早分叉

在那次故障里,属于这一层的是:

  • promo-cache 超时
  • cache miss 异常升高
  • 热 key 回源数上升

它们未必最响,也未必第一时间有人感知,但最接近那块第一张倒下的牌。

第二层:放大层

这层信号说明故障已经不只停在起点,而是在系统里开始传导和放大。

那次对应的是:

  • promotion-service 连接池 pending
  • 订单服务工作线程占满
  • 同步重试次数上升
  • 消费积压开始出现

这一层最有用的地方,是告诉你事故是否已经从“一个点慢”变成“整条链在自激”。

第三层:结果层

这层是用户最容易感知、业务最容易报警的部分。

例如:

  • 网关 504
  • 下单超时率升高
  • 支付页白屏
  • SLA 告警

这层当然重要,因为它决定影响范围和升级动作。但它通常不是第一轮最值得追的“根”。

分层不是给监控平台看的,是给值班动作看的

很多团队做告警分层,最后会做成一份监控平台里的标签体系。颜色变了、目录变了、owner 也写清楚了,但现场还是慢。

原因是它没有和动作绑在一起。

那次之后,我们给三层告警各自配了完全不同的第一反应。

起点层告警响了,先做证据对齐

不是立刻拉所有人,而是先确认:

  • 影响的是哪条业务链。
  • 是单实例、单机房,还是全量。
  • 最近有没有变更、切流、回填、重试策略调整。

起点层的目标不是把事情说大,而是尽快把“哪条链在先坏”说清。

放大层告警响了,先判断要不要止血

如果放大层已经连续抬高,就别再把现场当成单点故障慢慢看。

这时更重要的是:

  • 重试要不要先关。
  • 批任务要不要暂停。
  • 非核心入口要不要限流。
  • 哪些动作低风险、可逆,而且能直接减压。

放大层不负责解释根因,它负责告诉你:再不动,系统会不会自己把自己拖穿。

结果层告警响了,先判断影响面和升级面

结果层不是没用,而是职责不同。

它更适合回答:

  • 这事影响多少用户。
  • 是不是需要业务方同步。
  • 是否需要升级响应级别。
  • 哪条核心链路必须优先保住。

如果把结果层拿来当第一定位入口,现场很容易一直盯着最外层症状打转。

这套分层不是在会议室里想出来的,是被第二次事故验证出来的

第一次事故后,大家其实还是半信半疑。

真正让这套分层站住脚的是两周后的一次相似事故。

那次也是告警一片红,但值班同学没有再从网关 504 开始。他先看起点层面板,发现最早抬头的是 inventory-cache 回源数和 Redis 慢命令;再看放大层,发现重试数和线程池 queue 还没完全起势;于是先把现场判断成“起点已出现,但还没进入全面放大”,没有一上来就做大动作。

结果是:

  • 5 分钟内就把主线收到了缓存层。
  • 没有因为最外层 504 把人全都拉去看网关。
  • 也没有因为数据库 RT 随后抬头,就把数据库当成先坏的那一层。

这时候团队才真正意识到,所谓“告警分层”并不是治理口号,而是值班现场在跟时间赛跑时,必须先拿到的一种顺序感。

真正该删掉的,不一定是噪音最多的,而是“没有收敛价值”的

告警重排之后,我们顺手删掉了一批以前觉得不能动的告警。

删的标准很简单:

  • 它是否帮助第一轮判断起点。
  • 它是否帮助判断事故是否已进入放大。
  • 它是否帮助判断用户影响和升级面。

如果一条告警满足不了这三类中的任何一种,只是在故障时固定跟着别的信号一起响,那它大概率就是“看着重要,现场没用”。

比如有些 JVM 次级指标,平时看很细,真出事时却只会在结果层统一变红。它不是不能留,而是不该继续站在值班主视图最前面。

这件事的边界也很清楚

如果你现在还处在“多个告警同时响,但连影响面都没切出来”的阶段,先去做第一轮范围切分,比重排告警更重要。像值班时看到多个告警同时响,第一轮该怎样做范围切分?这种问题,优先级比治理动作高。

如果你已经明确卡在某条慢链、超时风暴或回滚动作上,也别在这里兜。那已经不是“告警怎么分层”,而是要沿具体链路继续往下查。

这篇只处理一种场景:你们的告警并不少,但它们没有把值班现场收成一条故障链。

我后来最看重的,不是分了几层,而是值班群里的第一句话变了

以前事故刚开始时,群里第一句话通常是:

  • “谁看一下 504?”
  • “数据库是不是有问题?”
  • “怎么这么多告警?”

后来慢慢变成:

  • “最早抬头的是哪一层?”
  • “放大器起来没有?”
  • “外层结果已经影响到哪些用户?”

这不是措辞变化,而是值班习惯真的换了方向。

如果一套告警体系做完以后,现场第一句话还是“最红的是哪块”,那它再完整,也只是更大的告警墙。

真正有用的分层,应该让人更快找到第一张倒下的牌,也更快看清哪几张已经开始一起倒了。