Alertmanager 到底在做什么

学 Prometheus 的时候,很容易先记住一句话:

  • Prometheus 负责发现问题
  • Alertmanager 负责处理告警

但“处理告警”这四个字其实太大了。

第一次看到这些词的时候,很容易有一种感觉:

  • grouping
  • deduplication
  • inhibit
  • route

都认识,但放在一起又像四块散掉的拼图。

所以这篇不打算上来就背定义,而是想先把它看成一个完整动作:

Prometheus 像报警器,Alertmanager 像中控室。

前者负责发现“哪里出事了”,后者负责决定“这件事该怎么通知人”。


一、Prometheus 和 Alertmanager 的分工

先把边界分清楚。

Prometheus 做什么

Prometheus 根据你写的 告警规则(Alerting Rules) 持续判断:

  • 某台机器是不是挂了
  • CPU 是不是过高
  • 错误率是不是超阈值
  • 某个服务是不是不可用

如果条件满足,它就会产生一条 告警(alert)

例如:

alertname=InstanceDown
instance=10.0.0.1
severity=critical
env=prod
team=platform

这时候 Prometheus 的工作其实差不多就完成了。


Alertmanager 做什么

Alertmanager 接到这些告警后,开始处理“通知逻辑”:

  • 是不是几条相似告警可以合成一条
  • 是不是已经发过了,不用重复吵人
  • 是不是有更严重的根因告警在前面,次级告警可以先压住
  • 这条告警最终应该发给谁

所以可以把它理解成:

Prometheus 负责判断真假,Alertmanager 负责安排秩序。


二、grouping:告警分组

它是干什么的

分组(grouping) 的作用是:

把一批相似的告警合并成一条通知,避免消息风暴。

比如 3 台 Web 服务器同时挂了,如果不分组,你收到的可能是:

  • web1 down
  • web2 down
  • web3 down

但很多时候,你真正想知道的不是“第三台也挂了”,而是:

这一组服务正在一起出问题。


例子

假设 Prometheus 发来这些告警:

alertname=InstanceDown, job=node-exporter, severity=critical, instance=10.0.0.1
alertname=InstanceDown, job=node-exporter, severity=critical, instance=10.0.0.2
alertname=InstanceDown, job=node-exporter, severity=critical, instance=10.0.0.3

如果 Alertmanager 按下面这些标签分组:

group_by: ['alertname', 'job', 'severity']

那它会把这三条当成同一组,最后给你一条合并后的通知,大概像这样:

[CRITICAL] InstanceDown
job=node-exporter
3 instances are down:
- 10.0.0.1
- 10.0.0.2
- 10.0.0.3

怎么理解更自然

如果把告警想成一群人同时举手,grouping 就像班长先说一句:

“别一个一个喊,你们这批是同一类问题,我来一起报。”

它做的不是隐藏问题,而是把问题整理成人能消化的单位


三、deduplication:去重

它是干什么的

去重(deduplication) 的作用是:

同一件事如果已经通知过,就不要无休止重复发送。

这个特别重要,因为很多告警不是闪一下就结束,而是会持续一段时间。

比如一块磁盘满了,它不会因为你收到一次消息就自己变正常。Prometheus 继续评估规则时,还是会发现它处于 firing 状态。

如果没有去重,你就会被一模一样的消息反复轰炸。


例子

告警如下:

alertname=DiskFull
instance=10.0.0.8
severity=warning

第一次触发时,Alertmanager 会通知你:

[WARNING] DiskFull on 10.0.0.8

如果 10 分钟后磁盘还是满的,它不会把这当成“全新事件”,而会识别成:

还是同一件事,只是还没恢复。

这时候就会配合 repeat_interval 控制提醒节奏,例如:

repeat_interval: 4h

意思就是:

  • 第一次立刻发
  • 4 小时后如果还没恢复,再提醒一次
  • 中间不重复制造噪音

它解决的本质问题

去重处理的不是“真假”,而是“频率”。

它在回答一个很现实的问题:

同一个坏消息,要不要每分钟都重新喊一遍?

答案通常是,不要。


四、inhibit:抑制

它是干什么的

抑制(inhibit / inhibition) 最容易让人第一次看懵。

它的意思不是删掉告警,而是:

如果一个更关键、更上游的告警已经出现,那些明显只是连锁反应的告警,就先别单独通知。

也可以说成:

根因已经足够明显时,先压住次要噪音。


经典例子:主机挂了

假设 db-server-1 这台机器直接挂了。

它上面的服务也会跟着出问题,于是 Prometheus 可能同时产生:

  • InstanceDown
  • MySQLDown
  • AppHealthCheckFailed

如果这三条一起发,你会看到一堆表象。

但真正的根因往往是:

这台机器本身就已经挂了。

所以更合理的通知方式是:

  • InstanceDown
  • 暂时抑制 MySQLDown
  • 暂时抑制 AppHealthCheckFailed

例子配置思路

inhibit_rules:
- source_match:
alertname: InstanceDown
target_match:
severity: warning
equal: ['instance']

可以先这样理解:

  • 如果某个 instance 上已经出现 InstanceDown
  • 那同一个 instance 上的一些低级别告警
  • 就先不要单独发出来

比喻一下

如果一栋楼停电了,很多设备都会报错:

  • 电梯故障
  • 门禁异常
  • 摄像头离线

但这时候中控最先需要通知的其实是:

整栋楼断电了。

剩下那些衍生问题不是不重要,只是它们暂时不该抢话。


五、route:路由

它是干什么的

路由(route / routing) 的作用是:

把不同类型的告警,送到不同的人、不同渠道。

不是所有告警都该发到同一个群里。

比如:

  • 生产环境严重故障 → 值班电话 / PagerDuty
  • 普通 warning → 开发群
  • 数据库问题 → DBA
  • 安全相关 → 安全团队
  • dev 环境告警 → 只发测试群,别吵生产值班

例子

假设一条告警长这样:

alertname=HighMemoryUsage
severity=warning
team=backend
env=prod

Alertmanager 可以根据标签决定发给谁,例如:

route:
receiver: default-receiver
routes:
- match:
severity: critical
receiver: pagerduty

- match:
team: backend
receiver: backend-team

- match:
env: dev
receiver: dev-null

你可以把它想成一个分流口:

  • 严重的,直接叫人
  • 后端团队的,发给后端
  • 开发环境的,降噪处理

六、把四个动作串起来看

假设生产环境里,3 台 Web 机器同时宕机。

Prometheus 发现这些告警:

InstanceDown instance=web1 severity=critical team=platform env=prod
InstanceDown instance=web2 severity=critical team=platform env=prod
InstanceDown instance=web3 severity=critical team=platform env=prod

HTTPProbeFailed instance=web1 severity=warning team=backend env=prod
HTTPProbeFailed instance=web2 severity=warning team=backend env=prod
HTTPProbeFailed instance=web3 severity=warning team=backend env=prod

这时候 Alertmanager 大致会这样工作:

1)先分组 grouping

把 3 个 InstanceDown 合成一组,避免一口气发 3 条同类通知。

2)再去重 deduplication

如果 10 分钟后还没恢复,不会每轮评估都再发一次。

3)再做抑制 inhibit

因为 InstanceDown 已经说明主机挂了,所以同机的 HTTPProbeFailed 可以先压住。

4)最后走路由 route

由于它是:

  • env=prod
  • severity=critical
  • team=platform

所以最终发给生产值班和平台团队,而不是乱发到所有地方。


七、一个最容易记住的版本

如果你之后复习的时候不想重新看长文,可以只记这一段:

  • grouping:把相似告警合并,避免消息风暴
  • deduplication:相同告警不要重复通知
  • inhibit:根因告警出现时,压住衍生告警
  • route:把不同告警送到不同的人

一句话总结就是:

Alertmanager 不负责发现异常,它负责把异常整理成“该怎么通知人”。


八、我自己的理解

学到这里,我会觉得 Alertmanager 有点像“告警世界里的秩序管理员”。

Prometheus 负责说:

“这里有问题。”

Alertmanager 负责说:

“别急,一个一个来。哪些该合并,哪些别重复,哪些先闭嘴,最后该通知谁。”

所以它最核心的价值,不是多高级,而是很现实:

让人能在噪音里看见真正重要的东西。

监控系统如果只会“报”,不会“整理”,最后很容易把人训练成对告警麻木。

而 Alertmanager 干的,就是尽量别让这件事发生。