bigywater.tech
微服务 · 75

告警:持续时间、抖动与去重

告警为什么会抖动、重复、刷屏?for 和 keep_firing_for 各解决什么?分组、repeat_interval、抑制、静默怎么减少噪音?这篇用 Prometheus 3.15.0 告警规则和 Alertmanager 0.34.1 逐项量出来。

1 vs 20
20 个实例同时出问题时,group_by 是 [alertname] 与 [alertname, inst] 收到的 webhook 通知条数
36.3 s
repeat_interval 设 30 s 时,ClusterDown 第二次通知比第一次晚的时间(group_interval 6 s 的计时点)
0
被抑制的 InstanceDown 和被静默的 Silenced 收到的通知数(状态是 suppressed)

for 与 keep_firing_for

实测 · 本机执行输出
  规则                             | firing 通知次数 | firing 通知时刻(s) | resolved 通知次数 | resolved 通知时刻(s)
  -------------------------------+-------------+----------------+---------------+-----------------
  for: 0s                        | 2           | 38, 54         | 2             | 44, 78          
  for: 5s                        | 1           | 59             | 1             | 77              
  for: 15s                       | 1           | 69             | 1             | 81              
  for: 0s + keep_firing_for: 10s | 4           | 14, 44, 54, 84 | 2             | 50, 90          
  FlapFor0 的 webhook 通知明细(通知时刻 | 整条通知的状态 | 其中该告警的状态、startsAt、endsAt,时间都相对时间线起点):
      38.0 s | firing   | firing   start    35.0 end     nan
      44.0 s | resolved | resolved start    35.0 end    38.0
      54.0 s | firing   | firing   start    51.0 end     nan
      78.0 s | resolved | resolved start    51.0 end    76.0
  FlapKeep10 的 webhook 通知明细(通知时刻 | 整条通知的状态 | 其中该告警的状态、startsAt、endsAt,时间都相对时间线起点):
      14.0 s | firing   | firing   start    11.0 end     nan
      44.1 s | firing   | firing   start    11.0 end     nan
      50.1 s | resolved | resolved start    11.0 end    48.0
      54.0 s | firing   | firing   start    51.0 end     nan
      84.0 s | firing   | firing   start    51.0 end     nan
      90.0 s | resolved | resolved start    51.0 end    86.0
  for: 5s 和 for: 15s 要求条件连续成立这么久才从 pending 变 firing,3 秒的短暂异常到不了,只有持续异常才通知(通知时刻比异常开始晚 for 的时长再加 group_wait 3 s 和评估的延迟)。for: 0s 时,短暂异常有没有通知取决于它和 Alertmanager 分组计时(group_wait、group_interval)的相位:一个告警要在计时点到来时还处于 firing 才会发出 firing 通知,在计时点之前已经恢复的,Alertmanager 什么都不发——看上面 FlapFor0 的明细,三次短暂异常里发出通知的只有 startsAt 对应的那一次(具体是哪几次每次运行会不同)。keep_firing_for 在条件不再成立之后继续保持 firing 一段时间:FlapKeep10 的 startsAt 到 endsAt 是一整段,相隔 9 s 的三次短暂异常被合并成了一个告警,只发一次 firing 和一次 resolved;持续异常那次 firing 之后还有第二次 firing 通知,那是 repeat_interval 到期后的重复通知

for 过滤掉短暂异常,keep_firing_for 把相隔不远的几次合成一个告警;for: 0s 时短暂异常是否通知取决于计时相位。

分组

实测 · 本机执行输出
  分组方式                        | 第 100 到 125 秒 firing 通知的次数 | 通知里的告警总数 | 每次通知里的告警数(前几次)   
  ----------------------------+----------------------------+----------+------------------
  group_by: [alertname]       | 1                          | 20       | 20               
  group_by: [alertname, inst] | 20                         | 20       | 1, 1, 1, 1, 1, 1…
  按 alertname 分组时,20 个同样的告警合并成一条通知;按 alertname + inst 分组,每个实例一条通知,同一时间会来 20 条

group_by 决定一条通知里合并哪些告警,把 20 个实例的同类告警合成一条。

重复通知

实测 · 本机执行输出
  ClusterDown 的 firing 通知时刻(s):[104.1, 140.4];resolved 通知时刻(s):[152.1]。第一次通知在告警开始之后 4.1 s(group_wait 加上规则评估),第二次通知比第一次晚 36.3 s:repeat_interval 是 30 s,实际的间隔落在 group_interval(6 s)的计时点上,所以是 30 s 到 36 s 之间,直到恢复才发 resolved

持续的告警按 repeat_interval 重复通知,实际间隔落在 group_interval 的计时点上。

抑制与静默

实测 · 本机执行输出
  告警                        | firing 通知次数 | Alertmanager API 中的状态(ClusterDown 和 InstanceDown 取第 120 秒,Silenced 取第 70 秒)                                      
  --------------------------+-------------+------------------------------------------------------------------------------------------------------------------
  ClusterDown(critical)     | 2           | {'inhibitedBy': [], 'mutedBy': [], 'silencedBy': [], 'state': 'active'}                                          
  InstanceDown(warning,被抑制) | 0           | {"inhibitedBy": ["e38c8bef90d27264"], "mutedBy": [], "silencedBy": [], "state": "suppressed"}                    
  Silenced(有静默,第 70 秒的快照)   | 0           | {"inhibitedBy": [], "mutedBy": [], "silencedBy": ["4d5ceda6-81d6-4e58-8e59-5fecc25394c8"], "state": "suppressed"}
  被抑制或被静默的告警仍然存在于 Alertmanager 里(状态是 suppressed),只是不发通知;去掉 critical 告警或者静默到期之后,它们才会通知
ERRORS {}

被抑制或静默的告警仍然在 Alertmanager 里,只是不发通知。

分步演示

告警
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Go / nginx / Envoy / etcd / Consul / Nacos / OpenTelemetry / Prometheus(按各篇注明用到哪些及版本);所有服务都是本机自己起的进程,端口 9150 以上,只监听 127.0.0.1,不连任何外部服务,不碰本机已有的实例;故障用 kill -9 进程、让连接断开或在代码里注入延迟与错误来制造;计时用 time.perf_counter,数字每次运行会有小幅抖动。Prometheus 3.15.0 与 Alertmanager 0.34.1,webhook 接收端是我写的 Python 服务;一条时间线(约 175 s)驱动所有情形,“短暂异常是否通知”的结果随运行不同(我跑过几次,通知的是不同的那一次),所以第一节正文里的时刻取自最后一次运行;分组与抑制的结果是确定的
    • 没有验证:邮件、IM 等真实的通知渠道;Alertmanager 高可用集群里的去重(gossip);mute_time_intervals;resend_delay 对 Prometheus 重发告警的影响;告警规则的 recording rule 配合;Grafana Alerting / Prometheus Operator 的 AlertmanagerConfig
    京ICP备2026067502号-1京公网安备11010502063487号