监控漫谈(四):告警设计——为什么你的告警让人“麻木”

凌晨三点,手机响了。你迷迷糊糊拿起来一看——“CPU 使用率超过 80%”。你打开监控看了一眼,业务完全正常,流量高峰而已。你叹了口气,把告警静音,继续睡。第二天,你又收到 30 条类似的告警。第三天,你把通知关了。恭喜你,你的告警系统已经“脑死亡”了。不是告警不够多,而是告警不够好。这篇文章聊聊怎么设计让人愿意认真对待的告警。

一、告警疲劳:比没有告警更可怕的事

“告警疲劳”(Alert Fatigue)是运维领域的经典术语。它的逻辑很简单:

告警太多 → 假告警太多 → 不再相信任何告警 → 错过真正的故障

这跟“狼来了”是同一个故事。区别在于,狼来了是小孩在喊,你的告警是机器在喊——机器不会觉得愧疚,它只会按照规则触发。

告警疲劳的典型症状:

  • 团队聊天群里每天几十上百条告警,没人回复
  • 值班人员把告警通知调到静音
  • 出了大故障后复盘:“告警不是报警了吗?”——“是吗?我没看到。”

如果你的团队有以上任何一种症状,那你的告警策略需要大修。

二、告警的黄金法则

法则一:告警必须能触发行动

这是告警设计的最高原则。如果一个告警响了,接收者不知道该做什么,那这个告警就不应该存在。

不该告警的例子

  • CPU 使用率超过 80%(可能只是正常流量波动,不需要人工干预)
  • 磁盘使用率超过 70%(还有 30%,不需要半夜把人叫起来)
  • 某个定时任务执行超过 10 秒(可能只是数据量变大了)

应该告警的例子

  • 用户支付成功率从 99.5% 降到 95%(用户正在受影响,需要立即介入)
  • API 返回 5xx 错误数连续 3 分钟超过阈值(服务出问题了)
  • 磁盘使用率超过 95% 且仍在快速增长(很快就要宕机了)

一个好的测试方法:每次加一条告警规则时,问自己“这条告警如果半夜响了,接收者应该做什么?” 如果答案不清楚,这条规则就不该存在。

法则二:告警应该是“症状”,不是“病因”

这个原则来自 Google SRE 的最佳实践。告警应该告的是“用户正在受影响”这个症状,而不是“可能存在问题的某个内部指标”。

告警"用户支付失败" ✓  —— 症状,用户已经受影响了
告警"数据库连接池达到 80%" ✗ —— 病因,用户可能还没受影响

为什么?因为“数据库连接池 80%”可能自己就好了,也可能不会影响用户,告这个只是在制造噪音。告警的目的不是让你知道“系统内部在干什么”,而是告诉你“用户正在遭遇什么”。

法则三:区分紧急程度

不是所有问题都需要凌晨三点把人叫起来。告警必须分级:

级别 含义 通知方式 响应要求
P0 / Critical 用户正在受影响,服务不可用 电话 + 短信 + IM 5 分钟内响应
P1 / Warning 有风险但尚未影响用户 IM + 邮件 30 分钟内处理
P2 / Info 值得关注但不紧急 邮件 或 不通知 工作时间处理

很多团队一上来所有告警都是 P0,结果就是没有 P0。

三、一个好告警的五个要素

当你写一条告警规则时,检查这五个点:

1. 明确的触发条件

不能是一个简单阈值,要有持续性判断:

# 不好的告警规则:瞬时触发
- alert: HighErrorRate
  expr: error_rate > 5%
  
# 好的告警规则:持续 5 分钟才触发
- alert: HighErrorRate
  expr: error_rate > 5%
  for: 5m

加一个 for 条件可以过滤掉大量的瞬时抖动,让告警的可信度大幅提升。

2. 清晰的告警标题

标题要告诉接收者“什么服务、什么问题、有多严重”:

  • 差:“告警:错误率过高”
  • 好:“[P0] 订单服务 - 支付接口错误率 12%(阈值 5%)- 持续 6 分钟”

3. 有用的告警详情

告警信息里应该包含排错所需要的关键信息:

  • 哪个服务
  • 什么指标异常
  • 当前值 vs 阈值
  • 持续时间
  • 相关的 dashboard 链接
  • 相关的 runbook(操作手册)链接

4. 合理的通知策略

不是一个告警就发给所有人。告警要发给“该知道的人”和“能处理的人”。

  • 应用相关告警 → 研发值班人员
  • 基础设施告警 → 运维值班人员
  • 严重 P0 告警 → 升级到技术负责人

5. 静默和抑制机制

这个经常被忽视但非常重要。告警应该支持:

  • 静默:计划内维护期间,不让告警骚扰人
  • 抑制:如果“服务器宕机”已经报警了,那“该服务器上的服务不可用”就不用再报了——前者已经包含了后者
  • 聚合:同类告警合并成一条,不要发 100 条

四、Alertmanager:Prometheus 生态的告警中枢

Prometheus 的告警通过 Alertmanager 来管理。它的核心流程是:

Prometheus 触发告警规则 → Alertmanager 接收 → 分组/抑制/静默 → 发送通知

一个简单的 Alertmanager 配置示例:

# alertmanager.yml
route:
  group_by: ['alertname', 'severity']
  group_wait: 30s        # 等 30 秒,同组告警一起发
  group_interval: 5m     # 同组告警有新告警时,间隔 5 分钟再通知
  repeat_interval: 4h    # 未恢复的告警每 4 小时提醒一次
  receiver: 'default'
  routes:
    - match:
        severity: critical
      receiver: 'oncall-phone'
    - match:
        severity: warning
      receiver: 'team-im'

receivers:
  - name: 'oncall-phone'
    webhook_configs:
      - url: 'http://phone-call-service/alert'
  - name: 'team-im'
    webhook_configs:
      - url: 'http://wechat-bot/alert'

关键参数说明:

  • group_wait:同一组告警等 30 秒再发,避免告警风暴中一个接一个的通知
  • group_interval:同一组告警中追加的新告警,至少间隔 5 分钟才通知
  • repeat_interval:持续未恢复的告警,每 4 小时提醒一次

这三个参数,精准控制了“告警的频率”,是避免骚扰的关键配置。

五、实践中常见的坑

坑一:白天配的规则,晚上才暴露问题

白天业务高峰可能很正常,晚上低峰时段那些“波动型”告警规则就炸了。任何新告警规则至少跑一个完整的业务周期(24h)再正式启用。

坑二:告警了但没人知道怎么处理

很多团队配了告警但没有 runbook。告警响了,值班人员打开信息一看:错误率超过阈值。然后就不知道该干嘛了。

每条告警规则都应该对应一个 runbook——一个简单的文档,告诉你这个告警意味着什么、第一步排查什么、第二步排查什么、谁可以帮忙。

坑三:恢复通知比告警还重要

很多团队只关注“什么时候报警”,完全忽略了“什么时候恢复”。恢复通知的意义是:你不用一直盯着监控了,已经好了。

Alertmanager 默认会发恢复通知,不要关掉它。

小结

告警的本质是让机器帮人“值班”,不是让机器替人“焦虑”。好的告警系统应该让值班人员信任它——每条告警都值得认真对待,每条告警都知道该做什么。如果你的告警系统做不到这一点,那它不是帮手,是负担。

从今天起,审查一下你现有的告警规则。删掉那些“响了也不知道该做什么”的,给剩下的加上 for 条件,补上 runbook。告警少了,但每一条都真正有用——这才是正确的方向。

下一篇,也是本系列的最后一篇,我们聊聊分布式链路追踪——当一次请求经过十几个微服务时,你该怎么知道它到底经历了什么。

每天前进一小步,就是一个新的高度!