一、这条线是怎么长出来的
运维告警最容易掉进的坑不是「不告警」,而是「告警太多,最后没人看」。很多站长一开始只在服务器上装一个发短信的脚本,磁盘满了发一条、服务挂了发一条;后来加了网站可用性检测,再加数据库慢查询、证书到期、备份失败、日志关键词、流量异常……每加一个来源,就多一份配置文件、多一份通知模板、多一个发送通道。等到某天凌晨手机连续震动二十分钟,你打开一看,七条消息其实来自同一次故障:磁盘写满,导致 MySQL 报错、PHP 报错、Nginx 返回 502、可用性检测失败、备份任务失败。七个来源,一个根因。
这时候绝大多数人的第一反应是「关静音」。而一旦开始静音,真正的告警也会被一起忽略。所谓把告警渠道收敛,不是把告警砍掉,而是把「谁在说、说什么事、危急程度如何」这三件事分层理顺,让同一次故障只吵一次,让不紧急的事情进一个不打断人的地方。本文讲的是一台单机(最多两台)的个人站,怎么做这件事,不涉及企业级值班体系。
二、先分清三类通知,而不是先挑工具
在选渠道之前,必须先给告警分类,因为不同类型的告警,对「快」和「不打扰」的要求完全相反。
第一类:人必须马上知道的。站点整体不可访问、磁盘接近写满、数据库不可写、证书即将过期且自动续期已连续失败、被大规模恶意扫描导致 CPU 打满。这类消息要能穿透手机的勿扰模式,代价是只允许极少数来源进入。
第二类:需要今天处理,但不必半夜爬起来。备份任务失败、某个定时任务没有按预期运行、日志里出现新的错误类型、单条监控曲线的趋势异常。这类进一个可以稍后翻看的地方,比如一个专门的通知群、一个邮件箱。
第三类:只用于回溯和复盘。每天的流量汇总、磁盘使用增长曲线、访问日志里的爬虫比例。这类根本不该「推送」,而应该落到面板或日报里,需要时自己去查。
分类做完,你会发现很多所谓「告警」其实属于第三类,它们本来就不该发通知。把它们从推送链路里摘出去,是收敛的第一步,也是收益最大的一步。一个常见的经验比例:原来 100 条推送里,真正属于第一类的大概只有 5 到 10 条。
三、选渠道的四个硬性判断
渠道本身没有绝对好坏,但对「个人站、无人值守、国内网络环境」这几个前提,有四个判断标准值得先想清楚。
1. 到达率。告警渠道的第一要求不是好看,而是能到。邮件依赖收件服务器和垃圾邮件策略,关键时刻可能进垃圾箱;短信需要付费通道且容易被运营商限速;群机器人在国内网络下最稳,但前提是那个 App 你手机上没有设置静音。
2. 噪音控制的粒度。好的渠道应该支持按级别分流,最好能在同一个工具里对不同级别设置不同提醒方式。如果所有消息都发同一个地方,你最终只会有两个选择:全部静音,或者全部吵。
3. 是否支持聚合。同一次故障往往短时间内触发多次告警。渠道层面如果支持「同一条告警 N 分钟内只提醒一次」,可以从根上减少噪音;不支持的,只能靠脚本自己做去重。
4. 依赖性。告警链路本身不能被监控对象拖累。把告警脚本写在同一台机器上,机器挂了就一条消息也发不出——这是最常见的「监控盲区」。至少要有一路探测来自站外,比如由另一台小机器或第三方拨测服务发起。
四、一个够用的分层结构
对个人站来说,我推荐的形态是「一个入口 + 两个出口 + 一块面板」,而不是装一个完整的监控平台。
一个入口:所有告警都先写到一个统一的采集点,可以是本机的一个本地 HTTP 端点,也可以是异地一台极小机器上的接收脚本。所有检查脚本只负责判断「有没有问题」并把结果发过来,不负责决定怎么通知人。这样以后换通知方式时,只改这一个地方,不用改十几个脚本。
两个出口:一级告警走「能叫醒人的渠道」,通常只有一个;二级告警走「稍后看」的渠道,可以是群消息或者邮件。不要给同一级别配三个渠道,那等于三倍噪音。
一块面板:用来放第三类信息和历史曲线。它的价值不在于实时,而在于出了问题以后能回答「什么时候开始的、之前是什么状态」。
这个结构的关键是把「检测」和「通知」解耦。检测脚本越简单越好,通知逻辑集中在一处,这样既能保证可靠性,也便于后来调整阈值和级别。
五、去重与抑制:让一次故障只吵一次
收敛噪音最有效的手段不是减少监控项,而是让同一个根因只产生一次提醒。做法有三个层次,从简单到复杂:
第一层,时间窗口去重。同一类告警在 30 分钟(或 1 小时)内只发第一条,后续只累加计数,到窗口结束时附一条「期间共触发 N 次」的总结。这一层几乎能砍掉一半的重复消息,实现成本也最低——只要在采集点维护一个简单的状态文件即可。
第二层,根因抑制。允许一条告警抑制另一条。比如「磁盘写满」已经发出时,同一台机器上的「MySQL 报错」「站点 502」都进入抑制状态,只在摘要里体现。手工实现的方式是给告警配一张简单的依赖表:磁盘类告警优先于服务类,服务类优先于可用性类。这不需要复杂的算法,一张几十行的映射表就够。
第三层,恢复通知合并。故障恢复时,不要逐个服务发「已恢复」,而是发一条汇总:「磁盘 + MySQL + 站点,均已恢复,持续时长 18 分钟」。恢复通知也有价值,但它应该是一封信,不是七封信。
有一个容易忽略的细节:抑制必须是有时限的。如果磁盘写满这条告警因为某种原因没能恢复,抑制就会一直生效,其它告警全被压住。所以抑制窗口一般设为一小时,超过就必须重新评估。
六、级别怎么定:三个维度,不要凭感觉
给告警定级时,最常见的错误是按「技术上有多严重」来定,而不是按「对读者的影响」来定。磁盘 IO 打满技术上看很严重,但如果站点访问正常,它就未必该叫醒人。
我通常用三个维度判断:
影响面:是全部读者受影响,还是只有后台、只有某个低频功能。
可自愈性:会不会自己恢复。临时性的连接数抖动通常几秒就过去,如果阈值设得太紧,每次都会告警。
可逆性:如果不处理,一小时之后会变成什么样。磁盘从 85% 到 95% 通常要几天,但写满之后站点立刻不可用——所以磁盘告警应该在 85% 就发出第一次,但要放在二级;到 92% 再升级为一级。
把这三个维度写成一句话的判断规则贴在配置文件的注释里,半年后回来改阈值时还能看懂当初为什么这么定。
七、阈值与持续时间:两个数字都要写
只写阈值不写持续时间,是所有告警系统噪音的最大来源。负载 5 分钟内冲到 20 可能是备份任务在跑,持续 30 分钟就有问题;连接数瞬间到 500 可能是爬虫突发,持续 10 分钟就值得关注。
我的经验是:一级告警用「短持续 + 相对高的阈值」,二级告警用「长持续 + 相对低的阈值」。例如磁盘使用率,二级是「超过 80% 持续 10 分钟」,一级是「超过 92% 持续 5 分钟」。这样既不遗漏缓慢恶化,也不被瞬时抖动打醒。
另外要避免只看平均值。平均值会掩盖短时间的极值,尤其对 CPU 和响应时间这类指标,用 P95 或最大值配合持续时间判断,比平均值可靠得多。判断指标是否选对,一个简单的方法:回想上一次真实故障,看这个指标在当时能不能明显看出来。
八、站外探测这一路不能省
本机监控有一个结构性问题:它和被监控对象同生共死。机器断电、系统卡死、网络断开,本机脚本既发不出告警,也无法证明自己活着。这就是「监控自身也需要被监控」的意思。
解决办法不需要复杂:找一台最便宜的异地小机器,或者用第三方的拨测服务,每隔一到五分钟请求一次首页的一个固定 URL,检查 HTTP 状态码和内容里是否有特定字符串(只检查 200 不够,很多错误页也返回 200)。连续两次失败才告警,避免网络抖动误报。
还有一层,是本机对自己心跳的「反向确认」:本机的定时任务每五分钟向站外服务发一次心跳,如果站外超过十五分钟没收到,就说明本机可能整体失联。这个思路成本极低,但能覆盖「本机监控全瞎」这种最难发现的情况。
九、上线顺序与降噪收敛节奏
不要一次性把所有的监控都接上。顺序建议是:先接站点可用性和磁盘,跑一周,确认这两条线不误报;再接服务和数据库,再跑一周;最后接日志关键词和趋势类。每接一类,观察一周的噪音比例,如果某一类一周内发了超过十条而只有一两条是真问题,就先改阈值或者降级,不要带着它继续堆。
一个月后做一次回顾,把所有发出过的告警列一张表,逐条标记「真问题」「阈值太紧」「本来就不该发」。这张表比任何监控工具都更能改善你的告警质量。
十、小结
告警渠道收敛的本质不是减少监控,而是减少打扰。先按「是否需要立刻知道」把消息分成三类,第三类直接不进推送链路;再用一个入口、两个出口、一块面板的结构把检测和通知解耦;最后用时间窗口去重、根因抑制和恢复合并,让一次故障只吵一次。阈值配持续时间,指标看分位数,站外那一路永远留好。做到这几点,凌晨三点的电话才会真的有意义。