Prometheus 告警治理:减少告警风暴比多加规则更重要
一、告警风暴的本质是"相关性"没处理好
Prometheus 告警规则写起来很容易:配一个expr,设一个for持续时间,再配上labels和annotations,告警就上线了。但很多团队的告警系统用着用着就变成了"告警风暴":一个数据库慢查询,触发了数据库告警、应用延迟告警、队列积压告警、用户体验告警……最后值班人员的手机被轰炸到关机。
告警风暴的本质不是"规则写多了",而是没有处理好告警之间的相关性。数据库慢查询是根因,其他都是次生告警。如果不能把根因告警和次生告警区分开,值班人员就要在告警风暴中手动找根因,效率极低。
告警治理的第一原则:能聚合的告警一定要聚合,能抑制的告警一定要抑制。
二、告警聚合:用标签把相关告警归类
graph TD A[原始告警] --> B{判断是否同类} B -->|是| C[聚合到同一个 Alert Group] B -->|否| D[单独发送] C --> E[发送一条聚合告警] D --> F[发送单条告警] G[告警聚合配置] --> H[按 service + severity 聚合] G --> I[按 cluster + namespace 聚合] G --> J[按 alertname 聚合] style C fill:#bfb,stroke:#333 style E fill:#bbf,stroke:#333Prometheus 的 Alertmanager 提供了强大的告警聚合能力,核心是route配置中的group_by字段。我们团队的实践是:
按服务 + 严重等级聚合:同一个服务的同一严重等级的告警,在 5 分钟内发生的,聚合到一条通知里。
# alertmanager.yml 关键配置 route: group_by: ['service', 'severity'] group_wait: 30s # 等待 30s,让相关告警一起到达 group_interval: 5m # 聚合窗口 5 分钟 repeat_interval: 4h # 已发送的告警,4 小时内不重复发送 routes: # P0 告警立即发送,不聚合 - match: severty: critical group_wait: 0s receiver: 'p0-oncal' # 非 P0 告警按服务聚合 - match_re: service: .* group_by: ['service', 'severity'] receiver: 'default'按拓扑关系聚合:如果一个服务的告警是因为下游服务故障导致的,应该只发下游服务的告警。我们在服务拓扑中标注了dependency标签,Alertmanager 会根据拓扑关系自动抑制上游服务的告警。
三、告警抑制:根因告警之外的不要重复发
告警抑制是比聚合更进一步的手段。如果 A 告警的发生必然导致 B 告警,那 B 告警就应该被抑制。
Alertmanager 的inhibit_rules就是干这个的:
# alertmanager.yml 抑制规则配置 inhibit_rules: # 如果同一个服务有 critical 告警,抑制 warning 告警 - source_match: severty: 'critical' target_match: severty: 'warning' equal: ['service'] # 如果集群级别告警(比如整个集群网络故障),抑制该集群内所有服务的告警 - source_match: alertname: 'ClusterNetworkDown' target_match_re: alertname: .* equal: ['cluster'] # 如果节点告警,抑制该节点上所有 Pod 的告警 - source_match: alertname: 'NodeDown' target_match_re: alertname: .* equal: ['node']抑制规则要谨慎配置,否则会漏掉重要告警。我们的做法是:先在 staging 环境运行一周,观察抑制效果,确认没有误抑制后再推到生产。
四、告警质量评估:四个关键指标
告警系统上线后,要持续评估告警质量。我们关注四个指标:
1. 告警准确率(Precision):发出的告警中,有多少是真的需要人工介入的?
- 目标:≥ 90%
- 计算方法:人工确认需要处理的告警数 / 总告警数
- 优化方法:删除误报率高的告警规则,提高
for阈值
2. 告警召回率(Recall):生产事故中,有多少被告警捕获到了?
- 目标:≥ 95%
- 计算方法:告警捕获的事故数 / 总事故数
- 优化方法:补充监控盲区,降低告警阈值
3. 告警平均响应时间(MTTR):从告警触发到开始处理的平均时间。
- 目标:P0 < 5min, P1 < 15min
- 优化方法:优化 on-call 排班,改进告警通知渠道
4. 告警疲劳度:每个 on-call 人员平均每天收到多少条告警?
- 目标:≤ 5 条/天(不包括自动恢复的告警)
- 优化方法:提高告警阈值,删除低价值告警
# 告警质量评估脚本(简化版) from datetime import datetime, timedelta from prometheus_api_client import PrometheusConnect prom = PrometheusConnect(url="http://prometheus:9090", disable_ssl=True) def calculate_alert_quality(start: datetime, end: datetime): """计算指定时间段的告警质量指标""" # 查询所有触发的告警 alerts = prom.get_alerts(start_time=start, end_time=end) total_alerts = len(alerts) valid_alerts = sum(1 for a in alerts if a['labels'].get('valid') == 'true') captured_incidents = sum(1 for a in alerts if a['labels'].get('incident_id')) precision = valid_alerts / total_alerts if total_alerts > 0 else 0 recall = captured_incidents / total_incidents(start, end) # 假设有 incident 管理系统 return { "total_alerts": total_alerts, "precision": f"{precision:.2%}", "recall": f"{recall:.2%}", "avg_alerts_per_day": total_alerts / (end - start).days, } def total_incidents(start: datetime, end: datetime) -> int: """从 incident 管理系统查询事故总数(示例代码)""" # 实际实现要对接你们的 incident 管理系统 return 42 # 假设值五、总结
Prometheus 告警治理的核心不是"多加规则",而是减少告警数量、提高告警质量。聚合和抑制是两大核心手段;告警质量要持续评估,四个关键指标(准确率、召回率、响应时间、疲劳度)要定期review。
落地时的关键三点:告警必须能聚合、根因告警之外的要抑制、告警质量要量化评估。做到这三点,告警系统才是运维的助手;做不到,就只是另一个需要被管理的噪声源。