凌晨2点17分,核心支付链路挂了。
MySQL主库连接超时,订单服务全面降级,交易成功率从99.9%断崖式跌到67%。系统里告警在疯转——Prometheus的Alertmanager队列里塞了47条待推送告警。但钉钉群安安静静,没有一条消息响起来。
40分钟后,值班同学被业务方电话叫醒。事故复盘时才发现:Alertmanager的钉钉webhook在凌晨1点52分就因为网络抖动断连了,重试策略配了但没生效,告警全部卡在队列里,一条都没推出去。
一、为什么告警会“漏推”?
那次事故的根因不复杂,但暴露的问题很典型。
Alertmanager本身不原生支持钉钉webhook,需要通过prometheus-webhook-dingtalk等中间件做转发。一旦中间件挂掉、网络闪断、或者webhook地址被钉钉限流,告警就卡在半路。
更麻烦的是,当时我们只配了一个钉钉机器人——单点,没有备用通道-。Alertmanager默认的重试机制在特定场景下会失效,告警就安静地躺在后台,等运维发现的时候故障已经持续了很长时间。
那次P0事故之后,我们重新设计了基于Hermes+Alertmanager的钉钉告警体系。以下是落地过程中总结的几个关键点。
二、分级路由:P0走三通道,P3走钉钉群
告警分级是告警体系的第一道防线-。我们的分级逻辑如下:
- P0(严重) :服务不可用、核心链路中断、数据丢失风险。必须同时走钉钉+电话+短信三通道,确保凌晨也能触达值班人
- P1(高) :服务降级、错误率突增、大量超时。走钉钉@值班人+企业微信群
- P2(中) :性能劣化、资源水位偏高。走钉钉群消息
- P3(低) :日常提醒、非紧急告警。走钉钉群消息,不@任何人
Alertmanager的route配置核心是按severity标签做路由分发:
route: group_by: ['alertname', 'severity'] group_wait: 10s group_interval: 10s repeat_interval: 12h receiver: 'default' routes: - match: severity: 'p0' receiver: 'p0-receiver' continue: true - match: severity: 'p1' receiver: 'p1-receiver'
P0走单独的高优先级receiver,配置钉钉+电话+短信三个渠道-。P1以下走常规钉钉群。
三、去重与收敛:别让告警风暴把钉钉群炸了
一个核心服务挂掉,可能会触发上下游几十个关联告警-。如果不做收敛,钉钉群会在几分钟内被几百条消息刷屏——真正重要的那条反而被淹没了。
Alertmanager的收敛靠三个参数控制:
- group_by:按什么维度聚合。我们配置group_by: ['alertname', 'cluster'],同一个告警名称+同一个集群的告警合并成一条推送
- group_wait:首次告警触发后等待多久再发送。配10秒,让同一批告警有时间聚合
- group_interval:同一组告警的发送间隔。配5分钟,避免同一故障反复刷屏
另外配了inhibit_rules(抑制规则)——如果某个服务已经触发了P0级别的“服务不可用”告警,那么同服务相关的P2/P3告警自动被抑制,不重复推送。
四、多通道备份:不能让钉钉成为单点故障
那次P0事故最痛的教训就是单点。现在的方案是:
- 主通道:钉钉群机器人(prometheus-webhook-dingtalk中间件转发)
- 备用通道:企业微信群机器人
- 应急通道:电话告警(仅P0)
Alertmanager配置多个receiver,路由规则里P0同时推送给钉钉和企业微信两个渠道。任何一个渠道挂了,另一个还能顶上。
五、消息模板:让告警一眼就能看懂
告警消息如果只是一堆JSON,值班人还要花时间解读——40分钟里哪怕省下5分钟解读时间都可能是救命稻草。
我们重写了Alertmanager的钉钉消息模板,每条告警必须包含:
- 告警名称和严重等级(P0/P1/P2)
- 故障实例(哪个服务、哪台机器)
- 触发时间与持续时长
- 当前指标值(比如错误率从1%飙到23%)
- 直达Grafana面板的链接
用Go template写模板,钉钉消息渲染成卡片式富文本,一眼就能看清问题在哪。
六、健康检查:告警通道本身也要被监控
这是最后一道防线——告警通道本身挂了怎么办?
我们在prometheus-webhook-dingtalk服务上额外暴露了一个健康检查端点,用Blackbox Exporter定期探测。如果中间件服务不可用,触发一条独立的“告警通道异常”告警,走备用渠道通知运维。
另外,在钉钉群里配置了一个“心跳告警”——每天早上8点自动推送一条测试告警。如果哪天没收到,说明通道有问题,不等故障发生就能提前发现。
七、写在最后
那次40分钟的P0漏推事故之后,我们花了三周时间把告警体系从头到尾重构了一遍。现在回头看,告警建设的核心其实就三件事:
第一,分级。P0和P3不能走同一条路。越紧急的告警,通道越冗余。
第二,收敛。不要让告警风暴把真正重要的信息淹没。group_by、group_wait、inhibit_rules配好,比堆更多的告警规则管用得多。
第三,备份。钉钉不是万能的,任何单一渠道都可能出问题。多通道冗余是P0告警的底线。
告警系统的价值不在于“能发出去多少条”,而在于“该收到的人是否在第一时间收到了”。如果40分钟后才被业务方电话叫醒,那这套告警系统跟没有也没什么区别。
