Ziwen

← 返回博客

写给未来自己的监控告警守则

去年有段时间,我的 Bark 每天能收到二十几条推送:某台 VPS 的 CPU 瞬时打满、某个探针超时了一次、磁盘使用率过了 80%……一开始我还会点开看,两周之后我已经练就了瞟一眼就划掉的本事。直到有一天,真正重要的那条——主站证书还有三天过期——就这么混在一堆噪音里被我划掉了。

那次事故之后我意识到一件事:告警系统的目标不是「尽可能多地发现问题」,而是「让每一条告警都值得被打断」。告警太多和没有告警是等价的,区别只在于前者还额外消耗你的注意力。这篇文章是我给自己立的规矩,写给未来那个又想加新告警的自己。

守则一:只有两种告警

我把所有告警分成两级,没有第三级。中间地带是告警疲劳的温床——「有点重要但不太重要」的告警最后一定会被无视,那还不如一开始就不发。

  • P1:必须现在处理。站点挂了啊、证书 72 小时内过期、备份连续失败两天、磁盘剩余不足 10%。这类告警直接推手机,允许在凌晨三点把我吵醒——因为它们定义上就是「不修会更糟」的事。
  • P2:知道就好。磁盘过了 70%、某台机器负载偏高、某个非关键服务重启过。这类不进推送,只进一个每周一封的摘要邮件。我看不看都行,看了也不用立刻做什么。

判断标准很简单,每条告警立项前问自己一句:「收到这条告警后,我会有一个明确的动作吗?」如果答案是「嗯……看一下吧」,那它就不配是 P1。「CPU 高了」没有动作,「磁盘快满了所以该清理或扩容」才有动作。没有动作的告警只是焦虑发生器。

守则二:先监控自己,再监控别人

监控系统本身挂掉是最阴险的故障——你不会收到任何告警,反而觉得天下太平。我的第一台监控探针跑在主站同一台机器上,某次整机宕机,监控跟着一起消失了,我还是从访客邮件里知道站点挂了的。

现在的做法是「互相盯梢」:探针服务监控所有业务,同时用一个独立的、极简的外部健康检查(就是别家厂商的一台小鸡上跑个 cron)定期戳探针的心跳接口。探针超过十分钟没心跳,外部检查就告警。这条链路上任何一环死了,总有人在叫。配置很朴素:

# /etc/cron.d/watchdog —— 每 5 分钟戳一次探针心跳
*/5 * * * * root curl -fsS -m 10 https://probe.example.com/api/heartbeat \
  || curl -fsS -X POST https://bark.example.com/push \
       -d "title=probehub is silent&level=critical"

同理,告警通道也要有备份。我的主通道是 Bark,但 P1 告警同时发一份邮件——推送服务挂了的时候,至少 SMTP 这种老古董还活着。

守则三:尊重自己的睡眠

P2 告警在北京时间 23 点到 8 点之间一律静默,攒进第二天早上的摘要。这一条刚立的时候我有点心虚:万一真出事呢?后来想通了——真出事的定义就是 P1,而 P1 不静默。如果我连自己的分级标准都不信任,那问题出在分级上,不是静默上。

还有一条配套规则:抖动的告警必须加宽限。探针连续失败三次才算挂、CPU 连续十分钟超限才算高。瞬时毛刺不配打扰人类。加了宽限之后,我的月告警量从一百多条掉到了个位数,而其中真正需要动手的,平均每月一到两条。

守则四:告警要写清楚「然后呢」

最后一条守则关于告警文案本身。凌晨三点被吵醒时,人的智商是会打对折的,所以每条 P1 告警我都要求包含三样东西:什么坏了、在哪、第一步干什么。比如「backup on s0 failed twice: run journalctl -u backup 查看,常见原因是 rclone token 过期」——最后那句是给三个月后已经忘了这套东西怎么搭的自己留的。

写告警文案时我把自己当成一个被半夜叫醒的、毫无上下文的新同事。事实上三个月后我就是他。

收敛之后

折腾完这一圈,我的告警从每天二十几条降到每周几条,手机推送重新变成了值得立刻看的东西。最有意思的变化是心态:以前收到推送的第一反应是「又来」,现在是「哦,得处理一下」。监控的终极形态大概就是这样——大部分时间里它安静得像不存在,而它开口的时候,你知道它没在说废话。