跳转至

Alertmanager 告警降噪实战:抑制器 + 路由树 + 静默配置四步降噪法

2024 年冬天,我们线上发生过一次事故:Prometheus 监控到了 300+ 条告警,运维群里 5 分钟内刷了 2000 多条消息。值班人看了 10 分钟才发现真正的问题——磁盘满,其余 299 条都是衍生告警。这件事之后,我们花了两周把 Alertmanager 告警降噪做了一遍,现在每天活跃告警不到 10 条,重要告警秒级触达。

告警风暴的根因:三层失控

一个健康的告警系统应该做到:重要告警不漏,次要告警不烦。生产环境告警失控,本质是三层出了问题:

第一层:告警规则层    —— for 时窗太短,抖动就报警
第二层:分组层        —— group_by 维度不对,同类告警散落各处
第三层:抑制层        —— 没有依赖关系,衍生告警全报

下面按这四步走,把告警从几百条降到个位数。

步骤一:给告警规则加 for 时窗

告警规则的 for 字段是最简单的降噪手段,很多人忘了加。

groups:
  - name: host-alerts
    rules:
      - alert: HighCpu
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 10m                    # ← 必须加!没有 for 就是瞬时抖动也报警
        labels:
          severity: warning
        annotations:
          summary: "CPU 使用率超过 80% 持续 10 分钟"

原则:

指标类型 建议 for 时窗 理由
CPU / 内存 5-10m 短时尖峰是正常的
磁盘使用率 5m 磁盘增长是渐变过程
进程存活 1m 进程崩了不能等
网络延迟 5m 网络抖动常见
错误率 3m 瞬时 500 不一定是问题

踩坑实录:我们把 HighCpu 的 for 从 0 改成 10m 之后,告警数量从每天 40 条降到 3 条——因为 90% 的 CPU 告警都是Deployment 启动时的短暂尖峰。

步骤二:正确设置 group_by

group_by 决定了同类告警如何合并。配错了,同一故障会产生几十条独立告警。

route:
  group_by: ['alertname', 'cluster', 'service']  # 按业务维度分组
  group_wait: 10s        # 等 10 秒收集同类告警一起发
  group_interval: 5m     # 同组告警 5 分钟内不重复发
  repeat_interval: 4h    # 未恢复告警每 4 小时提醒一次

group_by 错误示例(翻车):

# ❌ 按 instance 分组 → 同一 alert 在 10 个实例上各发一条,完全独立
group_by: ['instance']

# ✅ 按业务分组 → 同一故障的多个实例合成一条告警
group_by: ['alertname', 'cluster', 'service']

踩坑实录:有一次 Kubernetes 集群扩容,Alertmanager 因为 group_by: ['instance'] 给每台新 Pod 发了独立的 HighMemory 告警,30 台 Pod 瞬间 30 条告警。改成 group_by: ['alertname', 'namespace'] 后,整个 namespace 只报一条。

步骤三:配置 Inhibit 抑制器

抑制器是告警降噪的核心武器。它的逻辑是:当 A 告警存在时,自动屏蔽 B 告警,前提是 B 是 A 的衍生告警。

inhibit_rules:
  # 磁盘满时,抑制 inode 告警(磁盘满了 inode 肯定也满)
  - source_matchers:
      - severity = critical
      - alertname = DiskFull
    target_matchers:
      - alertname = DiskInodeFull
    equal: ['instance']

  # 节点 NotReady 时,抑制该节点上的所有 Pod 告警
  - source_matchers:
      - alertname = NodeDown
    target_matchers:
      - severity = warning
    equal: ['instance']

  # 集群级别的网络分区,抑制所有单实例告警
  - source_matchers:
      - alertname = NetworkPartition
      - severity = critical
    target_matchers:
      - severity = warning
    equal: ['cluster']

抑制器设计原则:

  1. 只在因果关系明确时配置,不要为了少报而抑制
  2. equal 字段必须精确,不然会误抑制其他实例的正常告警
  3. 先开 Inhibit,再验证——每天检查一次"被抑制的告警"列表,确认没有误伤

踩坑实录:我们配置过一条 NodeDown 抑制所有 warning 告警的规则,结果某次节点故障时,一条真正的 warning 级别磁盘告警被抑制了——那条磁盘告警其实和节点故障无关,是另一块磁盘的问题。后来把 equal: ['instance'] 加上,才修正了这个问题。

步骤四:路由树按 severity 分发

路由树解决的是"谁在什么情况下该收到什么通知"。

route:
  receiver: 'default-receiver'
  group_by: ['alertname', 'cluster', 'service']
  group_wait: 10s
  group_interval: 5m
  repeat_interval: 4h

  # P0 告警:直接电话 + 企业微信,30 分钟重复
  routes:
    - matchers:
        - severity = critical
      receiver: 'p0-oncall'
      repeat_interval: 30m
      continue: false

    # P1 告警:企业微信,4 小时重复
    - matchers:
        - severity = warning
      receiver: 'p1-wechat'
      repeat_interval: 4h
      continue: false

    # P2 告警:邮件,24 小时重复
    - matchers:
        - severity = info
      receiver: 'p2-email'
      repeat_interval: 24h
      continue: false

** receivers 配置示例 **:

receivers:
  - name: 'p0-oncall'
    webhook_configs:
      - url: 'http://alert-router:8080/p0'  # 转发到电话回调系统
    wechat_configs:
      - corp_id: 'your-corp-id'
        agent_id: 'your-agent-id'
        to_party: 'oncall-team'
        api_secret: '{{ secret }}/wechat_secret'

  - name: 'p1-wechat'
    webhook_configs:
      - url: 'http://alert-router:8080/p1'

  - name: 'p2-email'
    email_configs:
      - to: '[email protected]'
        send_resolved: true

  - name: 'default-receiver'
    webhook_configs:
      - url: 'http://alert-router:8080/default'

四个翻车案例复盘

案例 1:Silence 配错导致真告警被屏蔽

现象:维护窗口加了 Silence,结果维护结束后 Silence 还在,正常告警全被吞了。

根因:Silence 到期时间配错了——配的是维护开始时间而不是结束时间。

教训:加 Silence 时 double-check 到期时间,养成习惯:维护结束前手动验证 Silence 是否还在生效。

案例 2:Inhibit 误伤导致漏报

现象:节点故障时,所有 warning 告警被抑制,包括一块与节点故障无关的磁盘告警。

根因:Inhibit 规则 equal 字段不够精确,缺少 service 维度。

教训:每条 Inhibit 规则必须经过"反向验证"——问自己"这条规则在什么情况下会误抑制正常告警?"

案例 3:group_wait 太长导致告警延迟

现象:P0 告警发出时已经过了 5 分钟,值班人员说"等我看完这条再处理,结果第一条已经过时了"。

根因:group_wait: 30s 对于 P0 太长了,P0 应该 5s 内发出。

教训:不同 severity 的 group_wait 要分开配,P0 用 5s,P1 用 10s,P2 用 30s。

案例 4:repeat_interval 太短导致告警疲劳

现象:一条 P1 告警每 30 分钟重复发一次,值班人员看了两天后直接屏蔽了通知。

根因:repeat_interval: 30m 太短,告警疲劳导致忽略。

教训:P1 至少 2h,P2 至少 12h。告警疲劳比告警缺失更危险——人习惯了不处理。

降噪效果对比

指标 降噪前 降噪后
日均告警数 350+ 8-12
P0 告警发现时间 平均 15 分钟(在噪音中找) < 2 分钟
误报率(无效告警) ~40% < 5%
值班人员告警疲劳 高(每天刷几百条) 低(每天处理不到 10 条)

写在最后

告警系统的核心目标不是"报得全",而是"报得准"。降噪不是一次性工程,是需要持续维护的——每加一条告警规则,都要问自己:这条规则会不会产生噪音?会不会被其他规则覆盖?会不会和现有抑制器冲突?

把告警当成产品来做,降噪就是它最重要的用户体验。