Prometheus 告警实战:写 alerting rules、用 Alertmanager 做路由分组与抑制

Prometheus 告警实战:写 alerting rules、用 Alertmanager 做路由分组与抑制

很多团队把 Prometheus 装好、Grafana 图也画得漂漂亮亮,然后就没有然后了------真出故障的时候,没人盯着大屏,报警靠用户投诉。监控的最后一公里是告警,而这一公里恰恰最容易做烂:要么规则写得太敏感,半夜狂轰乱炸把人训练成"狼来了";要么阈值太宽,真挂了也不响。

这篇文章把告警链路走一遍:Prometheus 里写 alerting rules,Alertmanager 里做分组、路由和抑制,最后落到一个能收敛噪音的可用配置。

告警链路先理清

告警分两半,职责不同,别搞混:

  • Prometheus:负责"判断"。根据 PromQL 规则计算,满足条件就产生一条 alert,推给 Alertmanager。
  • Alertmanager:负责"投递"。接收 alert,做分组、去重、静默、抑制,最后按路由发到钉钉/邮件/PagerDuty。

阈值和触发逻辑写在 Prometheus;"发给谁、怎么发、要不要合并"写在 Alertmanager。

第一步:写一条不会误报的 alerting rule

新手最常见的错误是没有 for 字段,导致指标瞬间抖一下就报警。

yaml 复制代码
# rules/node.yml
groups:
  - name: node-alerts
    rules:
      # ❌ 反面教材:CPU 一飙高就报,毛刺也触发
      - alert: HighCpuBad
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80

      # ✅ 正确:持续 10 分钟高于阈值才算数
      - alert: HighCpuUsage
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 10m   # 持续满足 10 分钟才从 pending 转 firing
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.instance }} CPU 使用率过高"
          description: "CPU 已连续 10 分钟超过 80%,当前 {{ $value | printf \"%.1f\" }}%"

几个关键点:

  • for: 10m :表达式为真后,alert 先进入 pending 状态,持续满足 10 分钟才转 firing 真正发出。这一条能过滤掉 90% 的毛刺误报。
  • labels :给 alert 打标签(如 severity),Alertmanager 后面靠它路由。
  • annotations :给人看的描述,支持模板。$value 是表达式当前值,$labels.xxx 取 series 标签。

再看一个更实用的例子------服务不可用 ,注意用 absent 处理"指标彻底消失"的情况:

yaml 复制代码
      - alert: InstanceDown
        expr: up{job="api"} == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.instance }} 已宕机"

      # up 指标本身消失了(exporter 挂了/被删),up==0 都匹配不到
      - alert: ExporterMissing
        expr: absent(up{job="api"})
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "api 的监控目标彻底消失了"

写完在 Prometheus 配置里挂上规则文件,并指向 Alertmanager:

yaml 复制代码
# prometheus.yml
rule_files:
  - "rules/*.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets: ["alertmanager:9093"]

改完用 promtool 校验,别直接 reload 上线:

bash 复制代码
# 语法检查,CI 里也能跑
promtool check rules rules/node.yml
# 热加载,不用重启进程
curl -X POST http://localhost:9090/-/reload

第二步:Alertmanager 分组,别让 100 台机器发 100 条

假设一个机房断网,50 个实例同时 InstanceDown。如果不分组,你会收到 50 条钉钉------这就是告警疲劳的源头。group_by 让同一类告警合并成一条。

yaml 复制代码
# alertmanager.yml
route:
  # 按告警名 + 集群分组:同名同集群的合并成一条通知
  group_by: ['alertname', 'cluster']
  group_wait: 30s       # 第一条来了先等 30s,攒一批一起发
  group_interval: 5m    # 同组已有通知后,新增成员每 5m 再发一次
  repeat_interval: 4h   # 一直没恢复的,每 4h 提醒一次,别刷屏
  receiver: 'default-dingtalk'

receivers:
  - name: 'default-dingtalk'
    webhook_configs:
      - url: 'http://dingtalk-webhook:8060/dingtalk/webhook/send'
  • group_wait:分组第一次通知前的等待,给"同批告警"一个攒齐的窗口。
  • repeat_interval:未解决告警的重复提醒间隔,别设太短(几小时合适)。

第三步:按 severity 路由到不同渠道

warning 走群消息就行,critical 得电话叫醒人。用子路由 routes 做分流:

yaml 复制代码
route:
  group_by: ['alertname', 'cluster']
  receiver: 'default-dingtalk'
  routes:
    - matchers:
        - severity = "critical"
      receiver: 'oncall-pager'   # 严重的走电话/PagerDuty
      group_wait: 10s            # 严重告警等待更短,尽快发出
      continue: false            # 匹配到就停,不再往下走

receivers:
  - name: 'default-dingtalk'
    webhook_configs:
      - url: 'http://dingtalk-webhook:8060/dingtalk/webhook/send'
  - name: 'oncall-pager'
    webhook_configs:
      - url: 'http://pager-gateway:9000/trigger'

matchers 按 label 匹配,continue 决定命中后是否继续尝试后面的路由(默认 false,即命中即停)。

第四步:抑制规则,消灭"连带告警"

节点整个宕机时,它上面所有服务都会报 InstanceDown 之类的下游告警。你只想收到"节点宕机"这一条根因,不想被几十条连带告警淹没。这就是 inhibit_rules:

yaml 复制代码
inhibit_rules:
  # 当同一 instance 上有 critical 告警 firing 时,
  # 抑制掉同一 instance 上的 warning 告警
  - source_matchers:
      - severity = "critical"
    target_matchers:
      - severity = "warning"
    equal: ['instance']   # 只在 instance 相同时抑制

source 是"因",target 是"果",equal 指定"同一维度"。上面这条的含义:同一台机器上,critical 存在时就压掉它的 warning------因为你已经知道这台机器出大事了,warning 是噪音。

验证:别等真故障才发现配置错了

临时触发一条 alert 测投递链路,用 amtool:

bash 复制代码
# 手动塞一条告警进 Alertmanager,验证路由和渠道通不通
amtool alert add alertname=TestAlert severity=critical instance=test-1 \
  --alertmanager.url=http://localhost:9093

# 检查路由会把某条告警发到哪个 receiver,不用真触发
amtool config routes test --config.file=alertmanager.yml \
  severity=critical alertname=InstanceDown

amtool config routes test 特别有用:它模拟一条带指定 label 的告警,告诉你它会命中哪个 receiver,配置对不对一目了然。

小结

  • 告警链路分两半:Prometheus 判断(rules)+ Alertmanager 投递(分组/路由/抑制),阈值和渠道别写在一起。
  • 每条规则都加 for ,让它先 pending 再 firing,过滤毛刺误报;指标可能消失时用 absent。
  • 用 group_by 分组 合并同类告警,repeat_interval 设几小时避免刷屏。
  • 用 子路由按 severity 分流 渠道,用 inhibit_rules 抑制连带告警,只留根因。
  • 上线前 promtool check rules 校验、amtool config routes test 验路由,别拿真故障当测试。

一句话记忆点:告警的价值不在"响得多",而在"该响时响、不该响时闭嘴"------for、分组和抑制,就是让它闭嘴的三把锁。

相关推荐
excel12 小时前
研究 Vue 3 源码的收获
前端·vue.js
归秋14212 小时前
2026 企业 AI 办公工具选型指南:从评估框架到产品适配
大数据·运维·人工智能
Android系统攻城狮12 小时前
Linux Gstreamer深度解析之gst_audio_encoder_set_frame_max调用流程与实战(六十一)
android·linux·运维·音视频·gstreamer音视频·音视频进阶·gstreamer音视频进阶
硅基手札14 小时前
【Linux内核专栏 14】网络协议栈
linux·运维·网络协议
可乐鸡翅yeah_14 小时前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
lerhxx14 小时前
AI 应用如何高效优雅地恢复中断?—— "连接解耦 + 状态持久化"
前端·javascript
计算机魔术师14 小时前
METR 演示 AI 智能体如何篡改 Inspect 评估记录以掩盖不当行为
前端
前端snow15 小时前
ai agent --- 异步处理之 Rabbit MQ
前端
念何架构之路15 小时前
zap扩展生态与总结
java·前端·数据库
独孤九剑打醒他15 小时前
【原创开源】【概念设计】源 - 栅 - 漏 - 栅 - 源 横向双栅 MOS,低压交流多值逻辑芯片探索
前端·其他·架构·开源·硬件工程