适合读者:已经看过 Prometheus 指标,准备理解告警为什么迟迟不发、反复发送或没有恢复消息的初级运维人员。本文使用练习规则说明机制,时间参数是教学取值,需要按业务容忍时间调整。

1. 告警条件成立,为什么手机还没有消息
Prometheus 和 Alertmanager 负责不同环节:前者根据指标求值并产生告警状态,后者处理分组、静默、抑制和通知发送。接收端是否接受、展示和升级通知,又是后面的环节。
所以,“指标不对了”“告警已经 firing”“Alertmanager 收到了”“人收到了消息”是四个需要分别确认的事实。整体关系见 Prometheus Alerting overview。
这篇沿用抓取失败这个容易观察的场景,重点理解持续时间、通知计时和恢复,不把它等同于完整业务可用性。
2. 先把规则写成别人能接手的说明
一条实用告警至少说清楚:检查什么、什么条件算异常、允许持续多久、影响谁、谁来处理、先查看哪里。
例如:“ops-lab 的某个目标连续五分钟抓取失败,warning 级别,处理时先打开 Targets 查看最终 URL 和最近错误。”比一句“服务器挂了”准确,也更容易分派。
保存下面的 ops-alerts.yml:
groups:
- name: ops-lab-availability
interval: 30s
rules:
- alert: OpsLabScrapeFailed
expr: up{job="ops-lab"} == 0
for: 5m
labels:
severity: warning
environment: lab
annotations:
summary: '抓取失败:{{ $labels.instance }}'
description: 'ops-lab 的该目标持续抓取失败,请先查看 Targets 最近错误。'
这条规则只针对 job="ops-lab" 且仍有 up 时间序列的目标。up=0 表示抓取失败,目标从配置或服务发现中消失后,可能变成没有序列,需要另外设计缺失检测。也可以先阅读站内 up=0 抓取排查文章。
severity=warning 是一个标签约定。只有通知路由或值班系统按它处理时,它才会影响通知方式;仅增加这个标签不会自动发短信或打电话。
3. for 不是“每五分钟检查一次”
本例规则组每 30s 求值。首次观察到条件成立后,该告警实例进入 pending;同一标签集合持续满足条件达到 5m,再在相应求值点进入 firing。
在没有设置 keep_firing_for 的这份规则中,条件不再成立时,规则会在后续求值中撤销该活动告警。for 不会要求恢复也持续等待五分钟。状态含义见 Alerting rules 文档。
下面是假设求值稳定、没有重启和数据缺失的教学时间线:
| 相对首次异常时间 | up 值 | Prometheus 预期状态 |
|---|---|---|
| 0 分钟 | 0 | pending |
| 4 分钟 | 0 | pending |
| 5 分钟 | 0 | firing |
| 6 分钟 | 1 | 告警条件解除 |
真实的故障发生时间可能早于第一次被抓取和求值观察到的时间,所以不能把通知到达时刻简单算成“故障时间加五分钟”。
4. 不等待五分钟,也能检查规则状态的预期
安装了与环境匹配的 promtool 后,可以先验证规则文件,再使用合成输入做规则单元测试:
promtool check rules ops-alerts.yml
将下面内容保存为同目录的 ops-alerts.test.yml:
rule_files:
- ops-alerts.yml
evaluation_interval: 30s
tests:
- interval: 30s
input_series:
- series: 'up{job="ops-lab",instance="demo:19100"}'
values: '0x11 1x4'
alert_rule_test:
- eval_time: 4m
alertname: OpsLabScrapeFailed
exp_alerts: []
- eval_time: 5m
alertname: OpsLabScrapeFailed
exp_alerts:
- exp_labels:
job: ops-lab
instance: 'demo:19100'
severity: warning
environment: lab
exp_annotations:
summary: '抓取失败:demo:19100'
description: 'ops-lab 的该目标持续抓取失败,请先查看 Targets 最近错误。'
- eval_time: 6m
alertname: OpsLabScrapeFailed
exp_alerts: []
执行:
promtool test rules ops-alerts.test.yml
输入每 30 秒一个点,0x11 表示起始的 0 再重复 11 次;随后是 1x4。测试分别检查 4 分钟没有 firing、5 分钟出现指定告警、6 分钟恢复后没有 firing。
这验证的是规则对合成序列的求值,不会验证真实抓取、Prometheus 到 Alertmanager 的连接,或消息是否发送给人。测试文件结构见 官方规则单元测试说明。
5. 通知还要经过另一套计时
下面是一份独立练习用 alertmanager.yml。示例接收地址只是本机教学端点,需要有真正接受 Alertmanager webhook POST 的接收服务;不要把它当作已经配置好的聊天机器人地址。
route:
receiver: ops-lab-webhook
group_by: ['alertname', 'job', 'environment']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receivers:
- name: ops-lab-webhook
webhook_configs:
- url: http://127.0.0.1:18083/alerts
send_resolved: true
三个时间参数分别控制不同事情:
| 参数 | 本例含义 |
|---|---|
group_wait: 30s |
新通知组首次通知前,先等待一小段时间以收集相关告警 |
group_interval: 5m |
首次等待后,按这个周期检查既有组的新增或恢复变化并决定通知 |
repeat_interval: 4h |
没有组变化时,对仍未解决的告警安排重复提醒 |
repeat_interval 不是精确独立运行的闹钟,还受组检查周期及数据保留等条件影响。参数定义见 Alertmanager 配置文档。
本例按告警名、job、环境分组,让同类事件适当聚合。分组键过细会产生很多通知组,过粗则可能把不相关事件混在一起。是否加入集群、服务或负责人,要结合自己的组织方式决定。
6. 恢复通知为什么不一定立刻到
send_resolved: true 允许这个 webhook 接收恢复信息,但它不保证条件解除的瞬间就收到消息。通知组的检查周期、路由、静默、网络和接收端处理都可能影响到达时间。
同一通知组也可能同时包含仍在 firing 和已经 resolved 的成员。接收端应读取各条 alert 的状态,不能只看一条组摘要就把整个事件全部关闭。
调大 for 可以过滤短暂波动,却会延迟首次发现;调大 repeat 主要改变未解决事件的重复提醒,不会修复频繁触发和恢复的抖动。应先判断噪声来自指标、阈值、标签变化还是通知策略,再调整相应层。
可选的 keep_firing_for 能延后条件解除后的告警退出,但会改变恢复语义;使用前应确认版本支持,并把新的时间行为纳入规则测试。
7. 怎样验证整条通知链路
先检查文件,再在测试环境加载。规则文件要通过 Prometheus 的 rule_files 引用,Prometheus 还要配置 Alertmanager 的实际地址;只保存两个文件并不会自动把它们连起来。
如果安装了 amtool,可检查 Alertmanager 配置:
amtool check-config alertmanager.yml
按顺序做一次可控实验,并记录时间:
- 让专用练习目标出现已知抓取失败,确认
up=0。 - 在 Prometheus Alerts 页面观察 pending 与 firing。
- 在 Alertmanager 查看同一标签集合,确认通知路由及静默状态。
- 在接收端确认收到的告警、来源、时间和处理入口。
- 恢复练习目标,确认规则解除,并核对接收端的恢复信息。
若 Alertmanager 在容器里,配置中的 127.0.0.1 指向它自身的网络环境,接收器不在同一环境时要换成可达地址。正式启用前还应确认接收方知道这是测试,避免把教学故障当成真实事故。
8. 告警多时,先问“收到以后做什么”
需要立即处理的用户影响、需要工作时间处理的容量趋势、适合记录但不必打断人的变化,应有不同的处理方式。对每条会打断人的告警,尽量提供影响范围、负责人和可执行的排查入口。
计划维护可使用有时限和明确匹配范围的静默;相关故障的依赖关系可通过抑制处理。它们影响通知,并不会自动消除原始指标或修复服务。告警策略的设计原则见 Prometheus Alerting practices。
最终验收时,把故障触发、规则状态、首次消息、重复消息和恢复消息逐项对照。这样调整的才是可解释的告警流程,而不只是把一个时间数字改大。