告警体系:Alertmanager、PagerDuty、OnCall 与分级抑制
凌晨 3 点,值班手机响了。不是一次。是 87 次。同一个上游依赖超时引发了连锁反应——87 条告警,其中 85 条是下游服务”我也超时了”的抱怨,只有最后 2 条是说”上游 Connection Pool 耗尽了”——真正的根因。值班人花了 40 分钟在手机屏幕上翻到第 86 条。
SLO 工程 定义了”什么算用户影响”——Burn Rate 告警。本文回答下一个问题:Burn Rate 触发了之后,告警怎么路由、怎么合并、怎么抑制、怎么叫醒正确的人,且不让值班人在 87 条通知里迷失?
Alertmanager 是 Prometheus
生态中专门负责”告警治理”的组件。它的设计目标不是”转发所有
firing alert”,而是 grouping + inhibition + silence
+ route
四元组,把数百条底层规则压缩成少量可行动的通知。文中配置结构按
Prometheus Alertmanager 0.27 官方文档(A
级来源)编写;本环境未安装 Alertmanager /
amtool,配置语法以文档为准,部署前请在目标集群执行
amtool check-config(见附录 K)。
一、告警体系的分层架构
从 Prometheus Alert Rule 到值班手机的完整路径可以拆成八层。每一层解决不同问题;跳过任何一层都会在生产环境中以”告警风暴”或”该响不响”的形式反弹。
| 层级 | 组件 | 职责 | 典型失败模式 |
|---|---|---|---|
| L1 规则 | Prometheus alerting rules | 定义”什么算异常” | 阈值拍脑袋、无 runbook |
| L2 记录 | Recording rules | 预计算 Burn Rate 等 SLI | 规则未部署到 HA 副本 |
| L3 路由 | Alertmanager route |
按 label 选 receiver | 所有 critical 都打 Page |
| L4 分组 | group_by + timing |
合并同源告警 | group_wait 太短 |
| L5 抑制 | inhibit_rules |
隐藏衍生告警 | 规则过宽误抑制 |
| L6 静默 | silence / time_intervals |
维护窗口屏蔽 | 静默过期未清理 |
| L7 通知 | receivers (webhook/PagerDuty) | 送达渠道 | webhook 429 丢通知 |
| L8 排班 | PagerDuty / Opsgenie | 谁在值班、如何升级 | 排班表过期 |
1.1 数据流概览
flowchart LR
subgraph prom [Prometheus]
AR[Alert Rules]
RR[Recording Rules]
end
subgraph am [Alertmanager HA Cluster]
RT[Route Tree]
GR[Grouping]
IN[Inhibition]
RC[Receivers]
end
subgraph notify [Notification]
PD[PagerDuty Page]
JK[Jira Ticket]
SL[Slack Chat]
DB[Dashboard Log]
end
AR --> RT
RR --> AR
RT --> GR --> IN --> RC
RC --> PD
RC --> JK
RC --> SL
RC --> DB
1.2 Rules 层:与 SLO 的衔接
SLO 工程 §4 给出 6 条
Workbook 规则——3 条 Page、3 条 Ticket。Alertmanager
不修改 这些规则的 expr,只根据
labels.severity 路由:
| Prometheus label | Alertmanager 路由 | 通知渠道 |
|---|---|---|
severity: page |
receiver: pagerduty-oncall |
电话 + SMS |
severity: ticket |
receiver: jira-sre |
工单 |
severity: chat |
receiver: slack-infra |
Slack 频道 |
severity: log |
receiver: blackhole 或 null |
仅 Grafana |
反模式:在 Prometheus 规则里写
severity: critical 却期望 Alertmanager 自动区分
Page 和 Ticket——critical
没有统一定义,必须显式使用 page /
ticket / chat / log
四级(或团队等价命名,但文档化)。
1.3 与指标体系的关系
指标体系设计 中的 USE/RED 指标是 Ticket 和 Chat 级 的主要输入——CPU 饱和、磁盘错误、连接池使用率。它们解释 SLO 失败的根因,但不应直接触发 Page。唯一应触发 Page 的指标类告警是 SLO Burn Rate(及等价的全站 outage 探测)。
二、告警规则设计的铁律
Google SRE Book 第 6 章:一个好的告警必须满足 actionable——收到它的人知道该做什么,且不做就会造成伤害或错过修复窗口。
2.1 四大黄金法则
- Actionable(可操作):告警必须链到 runbook 第一步。Runbook 第一句不是”调查一下”,而是”打开 Dashboard X,确认指标 Y,若 Z 则执行 W”。
- Owner(有主):
teamlabel 指向负责团队。无 owner 的告警在 on-call 眼里等于 spam。 - Priority(有优先级):与 Alertmanager
route 一致的
severitylabel。 - Runbook(有手册):
runbook_url必须是稳定 URL——不要用 Confluence 无版本页面。
2.2 必须标签模板
# 每条 alerting rule 的 labels 最小集
labels:
severity: page # page | ticket | chat | log
team: checkout
service: checkout-api
runbook_url: "https://wiki.example.com/runbooks/checkout-burn-rate"# annotations 最小集
annotations:
summary: "checkout SLO 1h 燃烧率 {{ $value | printf "%.1f" }}×"
description: |
当前 1 小时窗口 Burn Rate 超过 14.4×,预计 30 天内消耗约 2% 错误预算。
Dashboard: https://grafana.example.com/d/slo-checkout
Runbook: {{ $labels.runbook_url }}2.3 规则分层:Page / Ticket / Chat / Log
| 级别 | 触发条件(与 SLO 联动) | 响应 SLA | 示例 |
|---|---|---|---|
| Page | Burn Rate ≥ 14.4×/1h 或 6×/6h 或 1×/3d(见 18-slo §4.1) | 5 min ack | CheckoutSLOBurnRateCritical1h |
| Ticket | Burn Rate ≥ 1×/6h 或 Workbook Ticket 规则 | 1 h | CheckoutSLOBurnRateWarning6h |
| Chat | 容量趋势、复制 lag、慢查询增长 | 工作时间 | PGReplicationLagHigh |
| Log | 非生产、周期性 cron 信息 | 无 | StagingDeployComplete |
2.4 反例目录
以下规则在多数团队应 降级或删除:
| 反例规则 | 问题 | 建议 |
|---|---|---|
CPU > 80% → Page |
不等价用户影响 | 改为 Chat;Page 只看 Burn Rate |
Pod restart > 3 → Page |
可能是正常滚动发布 | Ticket + 关联 deployment 事件 |
Disk > 85% → Page |
有缓冲时间 | Ticket,7 天趋势 Chat |
Any 5xx > 0 → Page |
瞬时尖峰误报 | 用 Burn Rate 或 for: 5m |
cert expires in 30d → Page |
有充足修复窗口 | Ticket 30d,Chat 7d |
2.5 PromQL 规则写作规范
groups:
- name: slo_checkout_pages
interval: 30s
rules:
- alert: CheckoutSLOBurnRateCritical1h
expr: slo:checkout:burnrate1h > 14.4
for: 2m
labels:
severity: page
team: checkout
service: checkout-api
runbook_url: "https://wiki.example.com/runbooks/checkout-slo"
annotations:
summary: "checkout 1h Burn Rate {{ $value | printf "%.2f" }}×"
description: "Page 级 SLO 告警。见 18-slo Workbook 规则 A。"
- alert: CheckoutSLOBurnRateWarning6h
expr: slo:checkout:burnrate6h > 1
for: 15m
labels:
severity: ticket
team: checkout
service: checkout-api
runbook_url: "https://wiki.example.com/runbooks/checkout-slo-ticket"
annotations:
summary: "checkout 6h Burn Rate {{ $value | printf "%.2f" }}×"for: 子句是降噪关键——Workbook 建议 Page 规则
2–5 分钟 pending,Ticket 15 分钟至 1 小时。
三、Alertmanager 深度实战
Alertmanager
配置四大核心块:global、route、receivers、inhibit_rules。Alertmanager
0.27+ 还支持 time_intervals
用于维护窗口路由。
3.1 完整
alertmanager.yml 示例
以下配置为合成示例,展示 route 树、多 receiver、inhibit、time_intervals 的完整结构。Webhook URL 和 integration key 为占位符——部署时替换为真实值。
# alertmanager.yml — 合成生产级示例
# 验证:amtool check-config alertmanager.yml
# 参考:Prometheus Alertmanager 0.27 官方文档
global:
resolve_timeout: 5m
smtp_smarthost: 'smtp.example.com:587'
smtp_from: 'alertmanager@example.com'
smtp_auth_username: 'alertmanager@example.com'
smtp_auth_password: '<secret>'
slack_api_url: '<slack-webhook-url>'
templates:
- '/etc/alertmanager/templates/*.tmpl'
# --- time_intervals:维护窗口 ---
time_intervals:
- name: weekday-business-hours
time_intervals:
- weekdays: ['monday:friday']
times:
- start_time: '09:00'
end_time: '18:00'
location: 'Asia/Shanghai'
- name: planned-maintenance
time_intervals:
- weekdays: ['saturday']
times:
- start_time: '02:00'
end_time: '06:00'
location: 'Asia/Shanghai'
# --- route 树 ---
route:
receiver: 'default-slack'
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
# 计划维护:非 Page 告警静默路由到 blackhole
- matchers:
- severity=~"chat|log|ticket"
mute_time_intervals:
- planned-maintenance
receiver: 'blackhole'
continue: false
# Page:SLO Burn Rate → PagerDuty
- matchers:
- severity="page"
receiver: 'pagerduty-primary'
group_wait: 10s
group_interval: 2m
repeat_interval: 1h
continue: true
# Ticket → Jira
- matchers:
- severity="ticket"
receiver: 'jira-sre'
group_wait: 1m
group_interval: 10m
repeat_interval: 12h
continue: true
# Chat → Slack 分团队
- matchers:
- severity="chat"
- team="checkout"
receiver: 'slack-checkout'
continue: true
- matchers:
- severity="chat"
- team="platform"
receiver: 'slack-platform'
continue: true
# Log 级:不通知
- matchers:
- severity="log"
receiver: 'blackhole'
continue: false
# 兜底:未匹配 severity 的告警
- matchers:
- severity=~"critical|warning"
receiver: 'slack-sre-escalation'
continue: false
# --- inhibit_rules ---
inhibit_rules:
# 集群级网络故障抑制 per-target 不可达
- source_matchers:
- alertname="NetworkDown"
- severity="page"
target_matchers:
- alertname=~"TargetDown|KubeletDown|NodeNotReady"
equal: ['cluster']
# Page 级 SLO 抑制同 service 的 Ticket
- source_matchers:
- severity="page"
target_matchers:
- severity="ticket"
equal: ['service']
# 上游 checkout 依赖故障抑制下游 timeout 类 Chat
- source_matchers:
- alertname="CheckoutDependencyDown"
- severity=~"page|ticket"
target_matchers:
- alertname=~"DownstreamTimeout.*"
equal: ['cluster', 'upstream']
# 全站 outage 抑制单服务 degraded(保留 Page 本身)
- source_matchers:
- alertname="GlobalOutage"
- severity="page"
target_matchers:
- severity="chat"
equal: ['cluster']
# --- receivers ---
receivers:
- name: 'blackhole'
- name: 'default-slack'
slack_configs:
- channel: '#alerts-unrouted'
send_resolved: true
title: '{{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}'
- name: 'pagerduty-primary'
pagerduty_configs:
- routing_key: '<pagerduty-events-api-v2-key>'
severity: '{{ if eq .CommonLabels.severity "page" }}critical{{ else }}warning{{ end }}'
description: '{{ .CommonAnnotations.summary }}'
details:
firing: '{{ .Alerts.Firing | len }}'
service: '{{ .CommonLabels.service }}'
runbook: '{{ .CommonLabels.runbook_url }}'
- name: 'jira-sre'
webhook_configs:
- url: 'https://jira-bridge.example.com/create-ticket'
send_resolved: true
http_config:
bearer_token: '<token>'
- name: 'slack-checkout'
slack_configs:
- channel: '#team-checkout-alerts'
send_resolved: true
- name: 'slack-platform'
slack_configs:
- channel: '#team-platform-alerts'
send_resolved: true
- name: 'slack-sre-escalation'
slack_configs:
- channel: '#sre-unlabeled-alerts'
send_resolved: true
title: '未分级告警需人工标注 severity'3.2 Route 树设计原则
- 最具体的路由在前:
team=checkout应在通用severity=chat之前(Alertmanager 按顺序匹配第一个 hit)。 continue: true用于 Page + Slack 双通道:Page 到 PagerDuty 的同时抄送 Slack war room——但避免 Ticket 也双发 Page。repeat_interval按 severity 分级:Page 1h 重复可接受;Chat 可 24h。- 兜底 receiver
必须存在:未匹配路由的告警进
#sre-unlabeled-alerts,每周清理并补 label。
3.3 Grouping 工程细节
Alertmanager grouping 的三个时间参数(官方文档定义):
| 参数 | 含义 | 推荐起点 | 设错后果 |
|---|---|---|---|
group_wait |
同组首条告警后等待多久再发送 | Page 10–30s,Ticket 1–5m | 太短→多条通知;太长→Page 延迟 |
group_interval |
同组新增告警的最小通知间隔 | 2–10m | 太短→风暴;太长→信息滞后 |
repeat_interval |
未 resolve 时重发间隔 | Page 1–4h,Ticket 12–24h | 不设→默认 4h;设 0→非法 |
group_by 标签选择:
# 推荐:按 alertname + 故障域
group_by: ['alertname', 'cluster', 'service']
# 反例:group_by: ['instance'] — 100 台机器 = 100 组通知
# 反例:group_by: [] — 所有告警一组,无关告警捆绑工程判断:Burn Rate Page 应按
service 分组——checkout 和 payment 同时 Burn
时应是两条 Page,不是一条。
3.4 Inhibition 规则设计
Inhibition 语法(Alertmanager 0.27+ 使用
matchers):
- source:已 firing 的”根因”告警
- target:应被抑制的”衍生”告警
- equal:source 与 target 必须在这些 label 上相等才抑制
设计 checklist:
- 画依赖图:上游挂 → 哪些下游 alert 必然 firing?
- 每条 inhibit 写注释说明假设
- 避免
equal: []过宽抑制 - 在 staging 用
amtool或 UI 验证抑制是否误伤
# 示例:数据库只读模式抑制所有 query timeout Chat
- source_matchers:
- alertname="PostgreSQLReadOnly"
- severity=~"page|ticket"
target_matchers:
- alertname="QueryTimeoutHigh"
equal: ['cluster', 'database']3.5 time_intervals 与维护窗口
mute_time_intervals 挂在 route 上——维护期间
Ticket/Chat 进 blackhole,Page 不应
mute(除非确认无用户流量)。
# 仅非 Page 路由挂 mute
- matchers:
- severity=~"ticket|chat|log"
mute_time_intervals:
- planned-maintenance
receiver: 'blackhole'维护前创建 Silence(UI 或 amtool)覆盖已知 firing 规则,比永久改 route 更安全——Silence 有过期时间。
四、告警风暴:机制与治理
4.1 风暴如何形成
典型链路:上游 Redis 连接池耗尽 → 50 个微服务 timeout →
每个服务 3 条规则(latency、error rate、health check)→ 150
条 firing alert → 若 group_by: ['instance']
且无 inhibit → 150 条 Slack/PagerDuty 通知。
sequenceDiagram
participant Redis as Redis 连接池
participant Up as checkout-api
participant Down as 50 下游服务
participant Prom as Prometheus
participant AM as Alertmanager
participant OC as OnCall 手机
Redis->>Up: 连接超时
Up->>Down: 级联 timeout
loop 每服务 3 规则
Prom->>Prom: 评估 alert 规则
end
Prom->>AM: 150 alerts firing
Note over AM: group_wait 过短<br/>无 inhibit
AM->>OC: 87 条 Page/Slack
OC->>OC: 40 min 找根因
Note over OC: 应只收到 1 条<br/>CheckoutDependencyDown Page
4.2 风暴治理三板斧
- Inhibition:
CheckoutDependencyDownpage 抑制DownstreamTimeout* - Grouping:
group_by: ['alertname','service'],group_wait: 30s - 规则减量:删除”每条 5xx 都 Page”类规则,统一为 Burn Rate
4.3 风暴事后复盘模板
| 字段 | 内容 |
|---|---|
| 根因 alert | CheckoutRedisPoolExhausted |
| 衍生 alert 数量 | 148 |
| 实际通知数 | 87 |
| 应通知数 | 2(1 Page + 1 Ticket) |
| 修复动作 | 新增 inhibit;合并规则 |
| 误报标注 | 85 条标注为 duplicate |
五、分级告警体系设计模板(与 SLO Burn Rate 绑定)
本节将 SLO 工程 §4 的 Workbook 阈值映射到 Alertmanager 路由与 OnCall 响应。这是全文的决策核心。
5.1 四级定义与 Burn Rate 对照
| 级别 | Burn Rate 条件(30d SLO=99.9%) | Alertmanager receiver | OnCall 动作 |
|---|---|---|---|
| Page | 1h ≥ 14.4× 或 6h ≥ 6× 或 3d ≥ 1×(持续) | pagerduty-primary |
5 min ack,开 war room |
| Ticket | 6h ≥ 1× 或 1d ≥ 1× 或 3d ≥ 1×(未达 Page) | jira-sre |
1 h 内认领 |
| Chat | 无 Burn Rate;容量/趋势类 | slack-* |
工作时间处理 |
| Log | 非 prod、信息性 | blackhole |
仅 Dashboard |
Burn Rate 定义(摘自 18-slo):
\[\text{burn\_rate} = \frac{\text{error\_rate}}{1 - \text{SLO}}\]
对 99.9% SLO,\((1 - \text{SLO}) = 0.001\)。14.4×/1h 表示按当前错误率,约 1 小时消耗 30 天预算的 2%。
5.2 端到端映射表
| Prometheus alert | severity | Burn Rate expr | AM route | PD urgency |
|---|---|---|---|---|
CheckoutSLOBurnRateCritical1h |
page | burnrate1h > 14.4 |
pagerduty | high |
CheckoutSLOBurnRateCritical6h |
page | burnrate6h > 6 |
pagerduty | high |
CheckoutSLOBurnRateCritical3d |
page | burnrate3d > 1 |
pagerduty | high |
CheckoutSLOBurnRateWarning6h |
ticket | burnrate6h > 1 |
jira | low |
CheckoutSLOBurnRateWarning1d |
ticket | 1d window > 1× | jira | low |
CheckoutSLOBurnRateWarning3d |
ticket | 3d window > 1× | jira | low |
NodeDiskTrend7d |
chat | N/A | slack-platform | — |
StagingDeployOK |
log | N/A | blackhole | — |
5.3 Page 准入清单
满足 任一 才可 Page:
- 用户 facing SLO Burn Rate 达 Workbook Page 阈值
- 合成探测确认全站 outage(blackbox
probe_success == 0持续 2m,且影响 prod) - 安全事件(未授权访问 confirmed)——超出本文范围,走安全 runbook
永不 Page:CPU、内存、磁盘百分比、单 Pod restart、cron 失败(除非 cron 是支付链路 SLI 组成部分)。
5.4 Ticket 与 Chat 边界
| 信号 | 级别 | 理由 |
|---|---|---|
| PG 复制 lag > 30s | Chat → Ticket 若持续 1h | 未直接 Burn API SLO |
| API Burn Rate 1×/6h | Ticket | Workbook 规则 D |
| 证书 14 天过期 | Chat | 有修复窗口 |
| 错误预算剩余 < 20%(Dashboard) | Chat 通知 TL | 非即时技术响应 |
5.5 分级 policy 文档片段(可粘贴到内部 wiki)
## Error Budget Alerting Policy v1.2
### Page(立即)
- 条件:任一用户 facing 服务触发 SLO Burn Rate Page 规则(见 Grafana dashboard slo-pages)
- 响应:5 分钟内 PagerDuty ack;15 分钟内 incident commander
- Override:仅 SRE Lead 可 suppress Page(需事后复盘)
### Ticket(1 小时)
- 条件:Burn Rate Ticket 规则 或 非 SLO 但影响单一内部系统
- 响应:Jira 工单 1 小时内认领
### Chat(工作时间)
- 条件:容量、趋势、非用户 facing 退化
- 响应:下一工作日 standup 跟进
### Log
- 条件:staging、信息性事件
- 响应:无六、PagerDuty 与 OnCall 工程
6.1 排班模型
| 模型 | 适用 | 优点 | 缺点 |
|---|---|---|---|
| 每周轮换 | 小团队、单时区 | 简单 | 交接边界易漏 |
| Follow-the-sun | 全球三时区 | 本地时间 humane | 协调成本高 |
| 主备叠加 | 关键支付链路 | 冗余 | 两人同时被叫风险 |
PagerDuty Schedule 定义”谁值班”;Escalation Policy 定义”无 ack 时叫谁”。
6.2 升级策略示例
stateDiagram-v2
[*] --> Triggered: Alertmanager Page
Triggered --> Acknowledged: L1 ack 5min内
Triggered --> EscalatedL2: 5min 无 ack
Acknowledged --> Investigating: 打开 runbook
Investigating --> Resolved: 修复验证
EscalatedL2 --> EscalatedL3: 15min 仍无 ack
EscalatedL3 --> Resolved: SRE Lead 介入
Resolved --> [*]
| 级别 | 等待 | 目标 | 通知方式 |
|---|---|---|---|
| L1 | 0 | Primary on-call | Push + 电话 |
| L2 | 5 min | Secondary backup | 电话 |
| L3 | 15 min | SRE Lead | 电话 + Slack exec |
6.3 Incident 生命周期
PagerDuty Incident 状态:triggered →
acknowledged →
resolved。严格流程:
- Trigger:Alertmanager 通过 Events API v2 创建 incident
- Ack:L1 确认”我在处理”——不是”我看到了 Slack”
- Resolve:Prometheus alert 恢复后 Alertmanager 发 resolved——PD 可 auto-resolve(需配置)
# Alertmanager pagerduty_configs 片段
pagerduty_configs:
- routing_key: '<integration-key>'
send_resolved: true
class: '{{ .CommonLabels.service }}'
component: '{{ .CommonLabels.alertname }}'
group: 'slo'
severity: 'critical'6.4 Runbook 必备结构
- 症状:Burn Rate 14×/1h,checkout 5xx 上升
- 诊断三步:Grafana SLO 面板 → 依赖 RED 面板 → 最近 deployment(Events)
- 缓解:回滚 / 扩容 / 熔断——每步有命令
- 验证:Burn Rate 回落、SLI 恢复
- 升级条件:15 min 无进展 → 叫 DBRE / 架构师
6.5 值班疲劳度指标
| 指标 | 健康范围 | 超标动作 |
|---|---|---|
alerts_per_oncall_shift |
< 5 需人工介入 | 告警审计 |
false_positive_rate |
< 20% | 调阈值 / 加 for |
mean_time_to_ack |
< 5 min(Page) | 排班或 PD 配置 |
pages_without_incident |
< 10%/月 | 规则降级 |
七、告警质量的持续治理
告警体系 6–12 个月无治理会退化为”全部 mute”。
7.1 每周告警审计
从 Alertmanager 或 Grafana OnCall 导出:
- 触发次数 Top 10 规则
- 无 ack 规则
- 同一 alert 重复 > 10 次/shift
对每条:actionable? → 否 → 删除;是但非紧急
→ 降级 severity。
7.2 告警归因
每条 Page 事后必须:
- 关联 Incident ID,或
- 标注
false_positive+ 原因 + 修复 ticket
未归因 Page 在月度 SLO 评审(18-slo §7.3)中问责。
7.3 季度清理 Sprint
- 删除 90 天未触发规则(或改为 recording only)
- 合并重复 expr 的规则
- 更新 runbook 链接有效性
7.4 Alertmanager 高可用
单实例 Alertmanager 挂掉 → 告警路由停止。最小 HA:
- 3 副本 +
--cluster.peergossip - Prometheus 配置 两个 AM 地址(或 K8s Service)
- 验证:kill 一个副本,通知不断
见 Prometheus HA §Alertmanager 部署。
八、工程坑点(真实场景)
8.1 group_wait
设太短
现象:同一 Redis 故障,3 秒内收到 checkout、payment、cart 三条 Page。
原因:group_wait: 0 或
5s,三个 service 的 alert 分属不同
group(group_by 含 service)。
修复:
- 根因级 alert 用
group_by: ['alertname','cluster']合并 - 或 inhibit 只留根因 Page
- Page 级
group_wait: 30s仍保持可接受延迟
8.2
repeat_interval 误解
现象:告警恢复后仍每小时收到重复 Page。
原因:repeat_interval: 1h
且 alert 在阈值边界抖动(flapping)。
修复:
- 增加 Prometheus
for:pending - 调整 expr 阈值或 hysteresis
repeat_interval不等于 0——0 在 AM 中无效,默认 4h
8.3 Webhook 限流与丢失
现象:Slack/钉钉/飞书”有时收不到告警”。
原因:Webhook 429/5xx,Alertmanager 不重试无限次——失败通知丢失。
缓解:
- 监控 Alertmanager
alertmanager_notifications_failed_total - Webhook 网关做队列缓冲
- 关键 Page 走 PagerDuty 原生集成,不只依赖 Slack webhook
- 钉钉/飞书:注意 QPS 限制(各厂商文档不同,部署前核对当前限额)
8.4
severity=critical 无 escalation
现象:critical 告警进 Slack 无人看。
修复:统一 severity 枚举与 route
一致;unlabeled 进 #sre-unlabeled-alerts 并
weekly 修复。
8.5 Inhibition 过宽
现象:真实故障被 suppress——Payment 真正挂时 checkout 的 Page 被误抑制。
修复:equal 加
service;staging 测试
inhibit;文档化每条规则假设。
8.6 Alertmanager 与 Prometheus 标签不一致
现象:route
匹配不到,severity=page 进了
default-slack。
修复:CI 中
promtool check rules +
amtool check-config;单元测试 alert label
集合。
8.7
send_resolved: false 的取舍
恢复通知丢失时 on-call 不知道何时停 war room——建议 Page
通道 send_resolved: true;Chat 可 false
减噪。
九、与 Prometheus HA 的集成
9.1 双 Prometheus 单 Alertmanager 集群
两个 Prometheus 实例评估相同规则 → 可能 duplicate alert。Alertmanager 通过 gossip 去重 相同 fingerprint 的 alert。
配置:
# prometheus.yml
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager-1:9093
- alertmanager-2:9093
- alertmanager-3:90939.2 避免 alert 标签 churn
pod label 随滚动变化 → grouping 失效。SLO
规则应使用 service、deployment
等稳定 label。
十、通知渠道集成要点
10.1 Slack
- 使用 dedicated webhook per team
- 模板区分 Page(@channel)与 Chat(无 mention)
10.2 PagerDuty Events API v2
routing_key按 service 拆分——便于 PD 内分 escalation policydedup_key默认由 AM 生成——同组 alert 合并为一个 incident
10.3 钉钉 / 飞书 Webhook
- 消息体大小限制——长 annotation 截断
- 关键词安全设置——URL 需含关键词
- 限流:超 QPS 返回 430/429——见厂商当前文档
10.4 Email
- 仅 Ticket/Log——Page 不用 email(延迟高)
- SMTP TLS 与 auth 配在
global
十一、落地清单
十二、关键概念回顾
- 告警目标:高置信度用户影响 + 正确紧急程度 + 正确值班人
- Grouping / Inhibition / Silence:治理三元组
- Page 只用于 SLO Burn Rate(及等价 outage)
- group_wait / repeat_interval:风暴与疲劳的关键旋钮
- Webhook 限流:通知丢失的真实原因
- 持续治理:Weekly audit + Quarterly cleanup
十三、下一步
告警体系就绪后,存储账单是下一个治理焦点——采样、保留期、冷热分层。下一篇 存储与成本。
上一篇:SLO 工程:错误预算、Burn Rate、多窗口告警
下一篇:可观测性存储与成本
参考资料
- Prometheus, Alertmanager, https://prometheus.io/docs/alerting/latest/alertmanager/
- Prometheus, Configuration, https://prometheus.io/docs/alerting/latest/configuration/
- Google, The Site Reliability Workbook, Chapter 5: Alerting on SLOs, O’Reilly, 2018
- Google, Site Reliability Engineering, Chapter 6: Monitoring Distributed Systems, O’Reilly, 2016
- PagerDuty, Response, https://response.pagerduty.com/
附录 A:amtool 常用命令
# 验证配置
amtool check-config alertmanager.yml
# 查看当前活跃 alert(需连接 AM API)
amtool alert query
# 创建 2 小时 silence
amtool silence add alertname=CheckoutSLOBurnRateCritical1h \
--comment "planned load test" \
--duration 2h
# 测试 route(Alertmanager 0.27+)
amtool config routes test --config.file=alertmanager.yml \
--tree --verify.receivers \
severity=page service=checkout本环境未安装 amtool——命令来自 Alertmanager 官方文档。
附录 B:告警模板
slack.tmpl
{{ define "slack.slo.title" }}
[{{ .Status | toUpper }}] {{ .CommonLabels.severity }} — {{ .CommonLabels.service }}
{{ end }}
{{ define "slack.slo.text" }}
{{ range .Alerts }}
*{{ .Annotations.summary }}*
Burn Rate alert — Runbook: {{ .Labels.runbook_url }}
{{ end }}
{{ end }}附录 C:Synthetic alert 测试步骤
- 在 staging Prometheus 注入高 error rate recording
- 确认
slo:*:burnrate1h超阈值 - 观察 Alertmanager UI grouping
- 验证 PagerDuty staging service 收到 1 条 incident
- 恢复 error rate,确认 resolved 通知
附录 D:与 Chaos 工程衔接
混沌工程 实验前: - 创建 silence 覆盖预期 Chat 告警 - 不 silence Page 规则——验证 Burn Rate 是否正常触发 - 实验后检查 false positive 归因
附录 E:Multi-tenant 路由预告
多租户
场景下 route 按 tenant 分叉——每 tenant 独立
PagerDuty service。本文单租户配置需复制 route 子树。
附录 F:常见问题
F.1 Page 和 critical 能否混用?
不建议。critical 在 Prometheus
社区无统一定义。使用 page|ticket|chat|log 并与
Alertmanager route 一一对应。
F.2 Burn Rate 告警和 5xx 告警能否并存?
可以,但 5xx 应为 Ticket/Chat。Page 仅 Burn Rate——避免双 Page。
F.3 一个 alert 能否同时 Page 和 Slack?
可以:continue: true 匹配 pagerduty 后再匹配
slack-warroom。
F.4 Silence 和 mute_time_intervals 区别?
Silence 是运行时 API/UI 创建,有过期;time_intervals 是配置内周期性维护窗口。
F.5 Alertmanager 挂时 Prometheus 会怎样?
Prometheus 仍评估规则,但通知堆积在 AM 恢复前可能延迟——必须 HA。
附录 G:案例:支付链路 Redis 故障
背景:checkout SLO 99.95%,200 微服务。
时间线: - T+0:Redis pool 满,checkout Burn Rate 升至 18×/1h - T+1min:Page 触发(单条,group_by service) - T+3min:inhibit 抑制 40 条 DownstreamTimeout Chat - T+12min:扩容 Redis connection,Burn Rate 降至 2× - T+25min:resolved
教训:若无 inhibit,T+1min 会收到 40+ Slack。
附录 H:案例:发布回归 Burn Rate 慢性
背景:canary 发布引入 0.5% 额外 5xx,未达 Page 阈值。
时间线: - T+6h:Ticket 规则
burnrate6h > 1 触发 - TL 在 standup 决定回滚
- 错误预算消耗 8%/月 而非 2%
教训:Ticket 规则抓慢性退化;Page 抓突发。
附录 I:告警规则审查记录表(模板)
| 规则名 | severity | 上周触发 | ack 率 | false+ | 动作 |
|---|---|---|---|---|---|
| CheckoutSLOBurnRateCritical1h | page | (导出填写) | |||
| NodeCPUHigh | chat | ||||
| PodRestart | ticket |
审查人:________ 日期:________
说明:数字须从 Alertmanager / Grafana OnCall 导出,切勿编造。
附录 J:按团队的 Route 子树示例
checkout 团队独立 war room,platform 团队走共享频道:
routes:
- matchers:
- severity="page"
- team="checkout"
receiver: pagerduty-checkout
continue: true
- matchers:
- severity="page"
- team="checkout"
receiver: slack-warroom-checkout
continue: false
- matchers:
- severity="ticket"
- team="checkout"
receiver: jira-checkout
- matchers:
- severity="chat"
- team="platform"
receiver: slack-platform原则:Page receiver 按 用户 facing 服务 拆分 PagerDuty service——便于 escalation policy 绑定正确 TL。
附录 K:本环境验证说明
| 项 | 状态 |
|---|---|
| OS | Linux WSL2(编写环境) |
| Alertmanager | 未安装 |
| amtool | 未安装 |
alertmanager.yml |
按官方 0.27 文档结构编写 |
建议验证:
amtool check-config alertmanager.ymlamtool config routes test --tree --verify.receivers severity=page service=checkout- Staging 注入 synthetic error rate,确认 1 条 Page + inhibit 衍生 Chat
与 18-slo 附录 K 环境说明一致。
附录 L:Inhibition 规则库(可复用片段)
L.1 Kubernetes 集群级
- source_matchers:
- alertname="KubeAPIDown"
- severity="page"
target_matchers:
- alertname=~"Kube.*"
equal: ['cluster']L.2 数据库只读
- source_matchers:
- alertname="PostgreSQLReadOnly"
target_matchers:
- alertname=~"QueryTimeout|ReplicationLag"
equal: ['cluster', 'database']L.3 全站 CDN 故障
- source_matchers:
- alertname="CDNOriginUnreachable"
- severity="page"
target_matchers:
- alertname=~"Origin5xxRate"
equal: ['region']每条规则在注释中写清 equal 字段假设——staging 误抑制代价高。
附录 M:Grafana OnCall 与原生 Alertmanager
Grafana Cloud OnCall 可替代 PagerDuty + 部分 AM 路由。迁移注意:
| 能力 | Alertmanager | Grafana OnCall |
|---|---|---|
| grouping/inhibit | 原生 | 需映射或保留 AM |
| escalation | 外部 PD | 内置 |
| silence | amtool/UI | OnCall UI |
混合架构(常见):Prometheus → Alertmanager(group/inhibit)→ OnCall webhook(escalation)。
附录 N:Slack / 钉钉 Webhook 集成要点
N.1 Slack
slack_configs:
- channel: '#sre-pages'
send_resolved: true
title: '{{ template "slack.slo.title" . }}'
text: '{{ template "slack.slo.text" . }}'
actions:
- type: button
text: 'Runbook'
url: '{{ .CommonLabels.runbook_url }}'N.2 钉钉(合成示例)
钉钉自定义机器人需
msgtype: markdown,且安全设置可能要求关键词。Alertmanager
原生无钉钉 receiver——通常用
prometheus-webhook-dingtalk 等中转:
webhook_configs:
- url: 'http://dingtalk-bridge:8060/dingtalk/webhook1/send'
send_resolved: true坑:钉钉群机器人约 20 条/分钟 限制(以当前开放平台文档为准)——告警风暴时 429,通知丢失。Page 必须走电话通道。
N.3 飞书
与钉钉类似,通过 webhook 中转。消息体长度限制——长 annotation 需截断。
附录 O:Alertmanager 配置语法版本
| 版本 | 匹配语法 | 说明 |
|---|---|---|
| < 0.22 | match / match_re |
已弃用 |
| ≥ 0.22 | matchers |
推荐 label="value" |
| ≥ 0.27 | time_intervals |
替代部分 silence 场景 |
迁移时全局搜索 match: →
matchers:。
附录 P:Alert 状态生命周期
Prometheus alert 状态:inactive →
pending(for: 窗口内)→
firing → resolved。
Alertmanager 侧:active →
suppressed(inhibit/silence)→
unprocessed 通知队列。
调试:
- Prometheus
/alertsUI 看 pending 是否过长 - Alertmanager
/api/v2/alerts看 suppressed 原因
附录 Q:Runbook 模板(Burn Rate Page)
# Runbook: {{ service }} SLO Burn Rate Page
## 1. 确认影响
- 打开 Grafana: slo-{{ service }}
- 当前 Burn Rate: ___× 错误预算剩余: ___%
## 2. 最近变更
- 查 Events 面板 / ArgoCD 最近 2h 部署
## 3. 依赖检查
- RED 面板: 5xx rate by dependency
- 若单依赖 → 联系 owner team
## 4. 缓解
- [ ] 回滚最近发布
- [ ] 扩容(HPA / 手动)
- [ ] 熔断非关键功能
## 5. 升级
- 15 min 无进展 → TL
- 30 min → 架构师
## 6. 事后
- 关联 Incident ID
- 标注 false_positive 或 root_cause附录 R:CI 中校验告警配置
# .github/workflows/observability.yml 片段
- name: Check Prometheus rules
run: promtool check rules rules/*.yml
- name: Check Alertmanager config
run: amtool check-config alertmanager/alertmanager.yml
- name: Test routes
run: |
amtool config routes test \
--config.file=alertmanager/alertmanager.yml \
--tree \
severity=page team=checkout本环境未运行 promtool——CI 模板供读者粘贴。
附录 S:更多抑制设计场景
| 根因 alert | 应抑制的衍生 alert | equal 建议 |
|---|---|---|
LoadBalancerUnhealthy |
BackendTargetDown |
lb, region |
KafkaBrokerDown |
ConsumerLagHigh(所有 consumer) |
cluster |
DNSResolutionFailure |
ExternalAPITimeout |
cluster |
CertificateExpired |
TLSHandshakeFailure |
cert_name |
设计方法:画 故障传播 DAG,每条边对应一条 inhibit 候选——再 pruning 避免 over-inhibit。
附录 T:OnCall 排班与 Burn Rate 联动
大促前:
- 确认 Page 规则未 silence
- 增加 L2 backup 到 escalation policy
- Chat 级容量告警提前 48h 处理——避免与 SLO 失败叠加
大促中:
- 仅 SLO Page 可 override suppress(需 SRE Lead 审批 + 事后复盘)
- Ticket 可 batch 到每日两次 digest
附录 U:告警指标(自监控)
# Alertmanager 通知失败率
rate(alertmanager_notifications_failed_total[1h])
/
rate(alertmanager_notifications_total[1h])
# 活跃 alert 数
alertmanager_alerts{state="active"}
# 被抑制 alert 数
alertmanager_alerts{state="suppressed"}
notifications_failed_rate > 0.01 → Ticket
修 webhook 网关。
附录 V:与 Events 关联
Events 面板标注
deployment 时间——Burn Rate Page runbook
第二步查变更。Grafana 关联:alert annotation + Loki
| json | event_type="deploy"。
附录 W:术语对照
| 中文 | 英文 | 组件 |
|---|---|---|
| 分组 | Grouping | Alertmanager |
| 抑制 | Inhibition | Alertmanager |
| 静默 | Silence | Alertmanager UI/amtool |
| 升级 | Escalation | PagerDuty |
| 值班 | On-call | Schedule |
附录 X:Grouping 场景演算
假设 Redis 故障触发 3 条 Page
规则(checkout、payment、cart 各一条 Burn
Rate),group_by: ['alertname','cluster']:
| 配置 | 通知条数 | 说明 |
|---|---|---|
group_by: ['service'] |
3 | 每 service 一条——合理若需分 team |
group_by: ['cluster'] |
1 | 合并为一条——适合同一 war room |
group_by: ['instance'] |
50+ | 反例 |
Page 级 group_wait: 10s
允许三条 service alert 进同一 group(若 group_by 不含
service)——值班人一次 ack 三个 incident 或 PD 合并
dedup_key。
附录 Y:与 18-slo 六条规则的完整映射
| Workbook 规则 | Prometheus alert | severity | AM receiver |
|---|---|---|---|
| A: 1h ≥ 14.4× | CheckoutSLOBurnRateCritical1h |
page | pagerduty |
| B: 6h ≥ 6× | CheckoutSLOBurnRateCritical6h |
page | pagerduty |
| C: 3d ≥ 1× | CheckoutSLOBurnRateCritical3d |
page | pagerduty |
| D: 6h ≥ 1× | CheckoutSLOBurnRateWarning6h |
ticket | jira |
| E: 1d ≥ 1× | CheckoutSLOBurnRateWarning1d |
ticket | jira |
| F: 3d ≥ 1× | CheckoutSLOBurnRateWarning3d |
ticket | jira |
Inhibit:severity=page 抑制同
service 的 severity=ticket——避免
Page 与 Ticket 双发同一事件。
Recording rules 名称须与 18-slo §3
一致:slo:checkout:burnrate1h 等。
附录 Z:Silence 最佳实践
# 计划 load test 前 silence Chat 级,保留 Page
amtool silence add severity=chat cluster=staging \
--comment "load test 2026-06-20" \
--duration 4h \
--author "sre-oncall"
# 切勿 silence severity=page(除非 SRE Lead 书面 override)Silence 过期后自动恢复——比改
alertmanager.yml 更安全。维护窗口用
time_intervals +
mute_time_intervals 处理重复性维护。
附录 AA:告警风暴演练 Checklist
附录 AB:PagerDuty Service 与 Team 映射
| PagerDuty Service | 对应 Prometheus team |
Escalation Policy |
|---|---|---|
| checkout-prod | checkout | checkout-ep |
| payment-prod | payment | payment-ep |
| platform-infra | platform | platform-ep |
Alertmanager pagerduty_configs.routing_key
按 service 路由——避免所有 Page 进同一 PD service 导致错误
escalation。
附录 AC:repeat_interval 与 flapping 数值示例
假设 alert 在阈值边界抖动:firing 2min → resolved 1min → firing。
| repeat_interval | 1h 内通知次数(近似) |
|---|---|
| 15m | 4 |
| 1h | 1 |
| 4h(默认) | 1 |
配合 Prometheus for: 5m 可显著减
flapping——先调 for,再调
repeat_interval。
附录 AD:Webhook 失败监控告警
# meta-alert — 告 Alertmanager 自身
- alert: AlertmanagerNotificationFailing
expr: |
rate(alertmanager_notifications_failed_total[5m])
/ rate(alertmanager_notifications_total[5m]) > 0.05
for: 10m
labels:
severity: ticket
team: platform
annotations:
summary: "Alertmanager 通知失败率 {{ $value | humanizePercentage }}"Meta-alert 用 Ticket 而非 Page——避免 AM 故障时的递归 Page 风暴。
附录 AE:Blackbox 与 SLO Page 并列
全站 outage 时 blackbox probe_success == 0
可与 Burn Rate 同时 Page——应用
group_by: ['alertname'] 合并为一条 war room
通知,或 inhibit 较低优先级 probe 只留 Burn Rate。
- alert: SiteProbeFailed
expr: avg(probe_success{job="blackbox"}) < 0.5
for: 2m
labels:
severity: page
team: platform附录 AF:国际化团队通知
Follow-the-sun 排班时 Alertmanager route 按
region label 分叉
receiver——severity=page +
region=apac → APAC PD schedule。避免 UTC 03:00
Page 打到美洲值班者。
附录 AG:告警文档化要求
每条新 alerting rule PR 必须含:
- severity 分级理由(对照 §5.3 Page 准入)
- runbook 链接
- inhibit 依赖说明
- 预期触发频率(order-of-magnitude)
- staging 验证截图或 amtool 输出(有环境时)
附录 AH:版本历史
| 版本 | 日期 | 变更 |
|---|---|---|
| v1.0 | 2026-06-11 | 提纲 |
| v1.1 | 2026-06-18 | 深化:完整 alertmanager.yml、风暴时序、SLO 分级模板 |
附录 AI:Alertmanager UI 调试
/#/alerts— active / suppressed- suppressed 项查看 inhibited by
/#/silences— 误 silence/#/status— cluster health
API:
GET /api/v2/alerts?active=true&silenced=false&inhibited=false
附录 AJ:DB 层 Ticket 路由
PG
21-monitoring 指标 severity: ticket,
team: dbre——不 Page API on-call。
附录 AK:Opsgenie 等价配置
opsgenie_configs 与
pagerduty_configs 结构类似——escalation 在 SaaS
侧重配。
附录 AL:告警命名规范
Page<Service><Condition><Window>
例:PageCheckoutBurnRate1h
附录 AM:维护窗口公告模板
[Maintenance] cluster=prod-eu-1 2026-06-20 02:00–06:00 CST
Chat muted; SLO Pages active. Silence: (id)
附录 AN:文档修订
v1.1(2026-06-18):深化 Alertmanager 配置、SLO 分级模板、风暴治理与附录 K 环境说明。
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【可观测性工程】SLO 工程:错误预算、Burn Rate、多窗口多燃烧率告警
SLO 不是定几个 99.9% 的数字,而是连接业务需求与工程决策的治理机制。从 SLI 定义、错误预算计算到 Google SRE 多窗口多燃烧率 PromQL 规则,并说明 DB 层 SLI 如何映射到服务 SLO。
【可观测性工程】真实事故复盘剧本:从指标抖动到根因的全链路追查
虚构但可复现的 checkout 服务事故全链路:SLO Burn Rate 告警后按 Golden Minute→Metrics→Traces→Logs→Profile→Events 五阶递进排障,含 PromQL/LogQL/kubectl 命令与三条分级剧本,交叉引用系列 01–22。
可观测性工程
从 Metrics、Logs、Traces 到 Profiling、eBPF、OpenTelemetry 与 SLO 治理,面向中国工程团队的可观测性系统化手册。全 25 篇。
【可观测性工程】指标体系设计:USE、RED、Golden Signals 与业务 KPI
USE 方法论适用于资源,RED 方法论适用于请求,Golden Signals 适用于服务——三套方法论各有其适用对象。本文从 Brendan Gregg、Tom Wilkie、Google SRE 的原始定义出发,构建覆盖资源→服务→业务的完整指标体系,并给出 Prometheus 命名规范、基数治理策略与可抄的指标清单。