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错误率过高。

  1. 数据源:Prometheus,指标为 http_requests_total,包含 status 标签。
  2. 规则表达式:
    rate(http_requests_total{status=~"5.."}[5m]) 
    /
    rate(http_requests_total[5m]) > 0.05
    意思是:过去5分钟内,5xx错误量占总请求量的比例超过5%。
  3. 阈值设置:5%作为初始阈值,后续根据实际调整。
  4. 聚合方式:按 service 和 instance 分组,这样每个实例的错误率独立计算。
  5. 告警级别: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 规则测试:信我,一定要测

你写好的规则,直接上线?我劝你三思。

我以前吃过亏。一条规则写出来,看着没问题,结果上线后一条告警都没触发。过了两天才发现,表达式的标签写错了,查询结果一直是空的。搞笑的是,监控面板上数据都是正常的,唯独告警规则不生效。

避坑指南:

规则写完后,至少做这三件事:

  1. 在查询页面验证表达式:确保能查出数据,并且数据值符合预期。
  2. 模拟临界值:如果阈值为5%,就造一条4.8%和5.2%的数据,看规则是否准确触发。
  3. 测试抑制和聚合:触发一条高优告警,看相关低优告警是否被正确屏蔽。

嗯,测试虽然烦,但总比半夜被错误告警吵醒要好得多。

告警规则配置决策流程 确定告警目标 选择数据源类型 系统指标(实时) 应用日志(上下文) 业务数据(趋势) 设置阈值(动态/静态) 配置聚合与抑制规则 测试 → 校准 → 上线 一个完整的告警规则,包含数据源选择、阈值策略、聚合抑制、分级定义,以及必不可少的上线前测试。 任何一步跳过,都可能导致误报或漏报。

好了,规则写好了,也测试通过了。接下来,怎么管理这些规则?怎么应对告警风暴?这些咱们后面再聊。