4. 告警规则配置:如何编写高效准确的告警规则
告警规则怎么写?说白了,就是告诉系统“什么时候该喊你”。
我见过不少团队,规则配置得又臭又长,一告警就是几百条,根本没人看。你想想看,这跟没人管有什么区别?
这一章,咱们就聊聊怎么把告警规则写“聪明”。目标就三个:少误报、不漏报、好维护。
4.1 先想清楚规则粒度:别搞“大而全”
很多新人喜欢写一个大规则,把所有异常都塞进去。比如:
- alert: AllServiceErrors
expr: sum(rate(http_requests_total{status=~"5.."}[5m])) > 0
这规则一出,但凡有一个5xx,立马告警。但说实话,单个5xx很多时候是偶发,不值得半夜把你叫起来。
我个人习惯,先按严重程度拆成三个梯队:
- P0(致命):服务挂了、数据写不进去了、核心接口大面积错误。必须立刻处理。
- P1(严重):错误率明显上升、延迟超过阈值。需要立即跟进。
- P2(警告):资源使用率偏高、非核心功能异常。可以等白天处理。
分好梯队,规则自然就清晰了。你想想看,半夜收到的告警如果是P2,你是不是想骂人?
4.2 规则表达式:少用“与”,多用“或”
嗯,这里要注意。很多规则用一堆 AND 串起来,看着严谨,实际非常容易漏报。
举个例子:
expr: rate(http_requests_total{status="500"}[5m]) > 0
AND
node_load1 > 5
这规则的意思是:只有当 同时 有5xx和负载高的时候才告警。但实际中,可能是某个代码bug导致5xx,负载并不高。这时候就漏报了。
避坑指南:
我曾经掉进过一个坑。写了一条规则,要同时满足CPU > 90% 和内存 > 85% 才告警。结果有一次内存泄漏,CPU飙到99%,内存才70%,告警没触发。整整20分钟后才被用户投诉发现。打那以后,我定了一条规矩:P0级别的规则,永远不要用AND。
正确做法是:核心指标单独写规则,每个规则有自己的阈值和告警级别。这样既不会漏,排查起来也快。
4.3 数据源选对,规则才有效
告警规则的数据源,一般有三种:系统指标、应用日志、业务数据。
| 数据源类型 | 典型指标 | 更新频率 | 适合场景 |
|---|---|---|---|
| 系统指标(Prometheus等) | CPU、内存、磁盘、网络 | 15秒 - 1分钟 | 基础设施监控,实时性好 |
| 应用日志(ELK/Loki等) | 错误日志、慢查询日志 | 1分钟 - 5分钟 | 业务异常排查,上下文丰富 |
| 业务数据(MySQL/ES等) | 订单量、成交额、用户数 | 5分钟 - 1小时 | 业务健康度监控,趋势分析 |
我个人建议:实时性要求高的选系统指标,需要上下文的选日志,看趋势的选业务数据。一个规则尽量只用一个数据源,混用容易出问题。
小技巧:
写规则前,先想清楚“这个告警我希望在多长时间内发现”。如果是3分钟内必须发现,那就别用业务数据,因为业务数据通常是分钟级甚至小时级延迟。
4.4 阈值设置:动态 vs 静态
静态阈值是最简单的。比如“CPU > 90%”就报警。但问题在于,不同业务、不同时段,CPU的正常范围可能差别很大。
我在项目中遇到过这么一个例子:夜里做数据备份,CPU长时间在95%以上,按静态阈值早该报警了。但这是正常操作啊。怎么办?用动态阈值。
动态阈值有几种常见方案:
- 基于时间段的阈值:比如白天阈值为80%,夜里阈值为95%。
- 基于基线的阈值:比如“CPU比过去7天同时段高出50%”才报警。
- 基于预测的阈值:用机器学习预测未来走势,偏离预测值就报警(适合高级玩家)。
说白了,静态阈值适合“一眼就能看出不对”的场景,动态阈值适合“需要结合上下文判断”的场景。新手建议从静态开始,慢慢加动态逻辑。
4.5 聚合与抑制:别让告警轰炸你
你有没有遇到过这样的场景:一个数据库挂了,结果几十台业务服务器同时报“数据库连接失败”?这就是典型的告警风暴。
怎么解决?两个方法:聚合 和 抑制。
- 聚合(Aggregate):把多个相关告警合并成一条。比如“3台服务器的数据库连接异常”,发一条而不是三条。
- 抑制(Inhibition):当一个高优先级告警触发时,自动屏蔽相关的低优先级告警。比如数据库挂了,就不再报“数据库连接失败”这种衍生告警。
Prometheus里有个 group_by 选项,就是用来做聚合的。Alertmanager里也可以配置抑制规则。
核心思路:
告警的目的是让人处理,不是让人看。所以,能合并的合并,能屏蔽的屏蔽。最终用户收到的,应该是一份清晰的“待办事项清单”,而不是一堆需要自己分析的原始数据。
4.6 实战:写一条靠谱的告警规则
说了这么多,咱们手写一条试试。
场景:Web应用的5xx错误率过高。
- 数据源:Prometheus,指标为
http_requests_total,包含status标签。 - 规则表达式:
意思是:过去5分钟内,5xx错误量占总请求量的比例超过5%。rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05 - 阈值设置:5%作为初始阈值,后续根据实际调整。
- 聚合方式:按
service和instance分组,这样每个实例的错误率独立计算。 - 告警级别:P1(严重),需要立即跟进。
最终规则配置大概长这样:
groups:
- name: webapp_alerts
rules:
- alert: High5xxRate
expr: |
rate(http_requests_total{status=~"5.."}[5m])
/
rate(http_requests_total[5m]) > 0.05
for: 2m
labels:
severity: P1
annotations:
summary: "{{ $labels.service }} 的 {{ $labels.instance }} 错误率过高"
description: "当前5xx比例:{{ $value | humanizePercentage }}"
for: 2m 的意思是,阈值持续超过2分钟才告警。这个参数很重要,能过滤掉大部分瞬时抖动。说白了,就是别让系统一惊一乍的。
4.7 规则测试:信我,一定要测
你写好的规则,直接上线?我劝你三思。
我以前吃过亏。一条规则写出来,看着没问题,结果上线后一条告警都没触发。过了两天才发现,表达式的标签写错了,查询结果一直是空的。搞笑的是,监控面板上数据都是正常的,唯独告警规则不生效。
避坑指南:
规则写完后,至少做这三件事:
- 在查询页面验证表达式:确保能查出数据,并且数据值符合预期。
- 模拟临界值:如果阈值为5%,就造一条4.8%和5.2%的数据,看规则是否准确触发。
- 测试抑制和聚合:触发一条高优告警,看相关低优告警是否被正确屏蔽。
嗯,测试虽然烦,但总比半夜被错误告警吵醒要好得多。
好了,规则写好了,也测试通过了。接下来,怎么管理这些规则?怎么应对告警风暴?这些咱们后面再聊。