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、分组和抑制,就是让它闭嘴的三把锁。

相关推荐
郭邯26 分钟前
从零撸了一个 HTML 实体编解码工具,顺便聊聊我和 AI 结对编程的日常
前端
樊小肆33 分钟前
DeepSeeker-Code源码导读12-Hooks四引擎
前端·人工智能·agent
xm_xm_xm_137 分钟前
TypeScript 7 个 核心特性
前端·typescript
Zkaisen42 分钟前
【Gitee】SSH 公钥、GPG 公钥、私人令牌的区别
运维·gitee·ssh
mONESY43 分钟前
手把手从零复刻「英文网页 AI 翻译」Chrome 插件(新手向)
javascript
pppiii44 分钟前
前端并发请求控制:5 种实现方案完整梳理
前端
请你吃div44 分钟前
Node 后端项目 Docker 自动部署教程(GitHub + 宝塔 + Self-hosted Runner)
后端·docker·node.js
HXSYS1 小时前
无人机库房管理标准化,《无人机装调维修师》规范存储运维
运维·无人机
牢姐与蒯1 小时前
Linux进程(四).进程优先级以及进程切换,进程调度
linux·运维·服务器·ubuntu