故障只持续了 5 分钟,手机却响了 200 次。值班群里"滴滴"声此起彼伏,等真正要动手时,已经没人看得清哪一条才是根因。告警风暴不是告警系统坏了,而是规则设计和依赖关系从来没被梳理过。
一、先判断:是"故障多"还是"告警风暴"
三个特征只要中两个,就是风暴:
- 同一分钟内爆发成百条,而不是零星几条;
- alertname 高度雷同,同一个指标在几十个实例上一起喊;
- 上游只有一条告警,下游一片红,根因数远小于告警数。
一句话判据:根因数 << 告警条数。
快速取证,先看谁是"告警大户":
bash
# 当前生效告警按名字聚合,看谁贡献最多条
curl -s localhost:9093/api/v2/alerts \
| jq -r '.[].labels.alertname' | sort | uniq -c | sort -rn | head
# 看它们是不是同一时间窗爆发
curl -s localhost:9093/api/v2/alerts \
| jq -r '.[].startsAt' | cut -c1-16 | sort | uniq -c
二、第 1 步:给规则加"持续时长",滤掉抖动
for 是最便宜的降噪开关。瞬时毛刺不该惊动人:
yaml
groups:
- name: node
rules:
- alert: NodeCPUHigh
expr: 100 - (avg by(instance)
(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 90
for: 10m # 持续 10 分钟才发,抖动自动滤掉
labels: { severity: warning }
annotations:
summary: "{{ $labels.instance }} CPU 持续高于 90%"
同时要问自己:expr 表达的是"机器累了"还是"用户不能用了"?CPU 打到 90% 不是故障,接口错误率上升才是。
三、第 2 步:分组与抑制,让同一件事只响一次
分组 把同源告警合并成一条通知,抑制让上游故障出现时下游闭嘴:
yaml
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s # 首次等待,攒一批再发,别设太小
group_interval: 5m # 同组有新告警时的合并间隔
repeat_interval: 4h # 未恢复告警的重发间隔,别设 5m
inhibit_rules:
- source_match: { severity: 'critical' } # 上游:节点/机房级故障
target_match: { severity: 'warning' } # 下游:被它带崩的实例告警
equal: ['cluster', 'instance']
抑制的含义是"源故障出现时,压制目标告警"。方向写反,真故障会被压住------这是最危险的一类配置错误。
四、第 3 步:分级路由,重要的才喊醒人
把告警当人来看待,按"要不要半夜叫醒值班"分级:
yaml
routes:
- matchers: [ severity="critical" ]
receiver: pager # 电话/短信,必须有人到
- matchers: [ severity="warning" ]
receiver: im-group # 群消息,工作时间处理
repeat_interval: 6h
反模式很常见:所有告警都投到同一个 500 人大群。结果全员开启免打扰,真故障没人看,这就是告警疲劳。趋势类、容量类的信息应该进日报和看板,不进人。
五、第 4 步:从"监控资源"转向"监控症状"
最吵的一类规则往往长这样:磁盘 80%、CPU 90%、内存 85%。它们既不代表故障,也回答不了"我该做什么"。
两条改造思路:
- 换成 RED / USE 方法:请求错误率、延迟、资源饱和度。对"用户能不能用"告警,而不是对"机器累不累"告警。
- 阈值告警改趋势告警:不要等磁盘满了才喊,提前预测:
promql
# 按近 6 小时趋势,预测 4 小时内将写满 → 有缓冲时间,不慌
predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 4*3600) < 0
六、第 5 步:闭环------每次风暴都要复盘
- 记录四个数:告警总条数、去重后条数、MTTA(响应时长)、误报条数;
- 每月清理一次规则:3 个月没触发过、每次都误报、没人认领动作的规则直接删掉;
- 做一次故障注入演练(kill 一个实例、断开一条依赖),看告警是否符合预期------静默的监控比没有监控更危险;
- 给告警链路本身加自检:Watchdog 心跳告警,收到才说明"没有告警"是真的没故障,而不是管道断了。
七、避坑清单
for: 0s是风暴的头号制造者,任何瞬时告警都会成灾。group_wait太短 → 每条一个通知;太长 → P0 迟到。从 30s 起步调。repeat_interval用 5m → 未恢复的告警每 5 分钟重来一遍,等于自己造风暴。- 抑制规则方向写反 → 真故障被压住,比不告警更危险。
- 用邮件当 P0 通道 → 没人看,等于没有告警。
- 测试环境告警发到生产群 → 天天"狼来了",很快就没人信。
- 只想删告警、不愿改规则 → 下次故障照样刷屏。
- 忽略告警疲劳:人一旦开始忽略告警,整套监控就失效了------降噪和加监控同样重要。
八、一图总结
先算根因数 → 加 for 时长 → 抑制分组去重 → 分级路由派人 → 复盘清理规则
(风暴定性) (滤抖动) (同一事一声) (P0 电话 P2 日报) (删误报)
小结 :告警的价值不在于"发得多",而在于"发了就一定有人动"。先算根因数、再加 for 时长、用抑制和分组去重、按级别选通道、每月复盘清理规则------五步走完,手机能安静下来,而真故障一条都跑不掉。