「谁值班」看起来是个排班问题,实际上是可靠性的地基。一个设计糟糕的值班体系会迅速腐蚀团队:告警天天响、大部分是误报、真正的问题被淹没、值过班的人第二天写不出代码,最后所有人都在想办法「不上班」。
值班工程(On-call Engineering)要做的,是把值班当成一个需要设计的系统:轮换怎么排、告警怎么分级、噪音怎么降、告警响了要做什么、值完班怎么交接和复盘、健康度怎么度量。本文逐条讲清这套系统。
1. 告警疲劳的成因
1.1 什么是告警疲劳
告警疲劳(Alert Fatigue):
值班人收到的告警数量超过其有效处理能力,
导致对告警「脱敏」——不再认真看,直接忽略或批量静音。
后果:
- 真故障被淹没在噪音里,MTTD(发现时长)反而变长
- 值班人长期处于应激状态,离职意愿上升
- 团队对告警系统失去信任,绕过告警直接看仪表盘
1.2 四个根因
根因一:阈值型告警泛滥
CPU > 80% 就告警 → 但没有一个用户因此受影响 → 纯噪音
根因二:无分级
磁盘 90% 和 核心服务宕机走同一条通道 → 重要告警被稀释
根因三:告警不可操作
收到「服务异常」,但不知道看什么、做什么 → 只能 escalate 或忽略
根因四:缺少抑制与关联
数据库抖一下,20 个下游服务同时告警 → 20 条噪音掩盖 1 个根因
1.3 健康的量级
一个可参考的健康标准(按值班班次计):
- 每班次「打扰型」告警(需要立即响应):< 2 条
- 每班次全部告警(含自动恢复):< 10 条
- 误报率(响了但无需行动):< 20%
- 夜间(00:00~08:00)告警占比:< 10%
超出这些量级,说明告警治理没做到位,而不是「系统太不稳定」。
2. 值班轮换设计
2.1 轮换的基本参数
轮换周期:
一周一轮(常见):交接成本低,但夜间负担集中在一人
一天一轮:负担分散,但交接频繁、上下文丢失
半天一轮(follow-the-sun):跨时区团队,白天覆盖,夜间无人
推荐:跨时区团队用 follow-the-sun(跟随太阳)实现 24 小时覆盖;
单时区团队用一周主班 + 一周后备,避免单人连续值夜。
2.2 主备与影子制度
三层结构:
主责(Primary):第一响应人,负责确认与处置
后备(Secondary):主责未在 SLA 内响应时接管(通常 5~15 分钟)
影子(Shadow):新人跟班学习,不直接响应,但全程旁听
# 值班排班(示意)
schedule:
rotation: weekly
handoff: "每周一 10:00"
layers:
- name: primary
response_sla: "5m"
- name: secondary
response_sla: "15m"
escalate_to: primary
- name: shadow
response_sla: "none"
purpose: "新人培训"
compensation:
- "值主班一周,次周调休 1 天"
- "夜间被唤醒超过 2 次,次日免除会议与发布"
2.3 可持续性设计
防止值班「劝退」的几条硬规则:
1. 主班不连续超过 7 天
2. 夜间被唤醒 ≥ 2 次,次日不安排重要工作
3. 值完主班后至少 1 天恢复期(不进主班)
4. 值班有明确的补偿机制(调休或津贴)
5. 新人必须先当影子至少一个轮换周期
6. 值班人数 ≥ 4,才能形成可持续轮换(否则等于轮值过密)
值班设计的具体组织形态(SRE 与 Dev 的责任边界、嵌入式值班)可参考 SRE 实践 中的组织模型部分。
3. 告警分级与路由
3.1 分级标准
分级应基于「用户影响」而非「技术指标」:
P1(Critical):核心业务不可用或大面积受影响 → 立即唤醒,全员响应
P2(High):部分功能降级或影响部分用户 → 立即响应,值班处理
P3(Medium):潜在风险或非核心功能异常 → 工作时间内处理
P4(Low):信息性通知,无需行动 → 只进渠道,不打扰人
3.2 分级路由
# Alertmanager 路由(示意)
route:
receiver: "default-slack"
group_by: ["alertname", "service", "cluster"]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- matchers: ['severity="critical"']
receiver: "pagerduty-p1"
group_wait: 10s
repeat_interval: 1h
- matchers: ['severity="high"']
receiver: "pagerduty-p2"
- matchers: ['severity="medium"']
receiver: "slack-ops"
- matchers: ['severity="low"']
receiver: "slack-info"
repeat_interval: 24h
路由的关键是「分流」:
P1/P2 走呼叫(PagerDuty/电话),P3 走 IM,P4 只归档。
如果所有告警都走呼叫通道,呼叫通道的价值就被稀释了。
3.3 升级路径
升级(Escalation)机制:
第一级:主责,5 分钟未确认 → 升级
第二级:后备,10 分钟未确认 → 升级
第三级:团队负责人 / 领域专家 → 30 分钟未确认 → 升级
第四级:事故指挥(Incident Commander)接管,启动事故流程
要点:升级不是「惩罚」,而是「防止告警无人响应」的兜底。
未确认(未 ack)才升级,而不是「未解决」就升级。
事故升级后的处置流程(指挥、沟通、复盘)可参考 事故响应 。
4. 降噪:去重、聚合、抑制、基于 SLO
4.1 去重与聚合
去重(Dedup):相同指纹的告警只保留一条(如同一实例同一指标重复触发)
聚合(Grouping):相关告警合成一条通知(如某服务的所有实例同时告警)
Alertmanager 的 group_by 决定聚合维度:
group_by: [alertname, service] → 同一服务同类告警合成一条
若按 instance 分组 → 每个实例一条,噪音爆炸
4.2 抑制
抑制(Inhibition):当高优先级告警存在时,抑制相关的低优先级告警
典型规则:
- 节点宕机 → 抑制该节点上所有实例的告警(否则几百条)
- 数据库主库故障 → 抑制下游服务的「依赖超时」告警
- 网络分区 → 抑制受影响区域的所有告警
# Alertmanager 抑制规则
inhibit_rules:
- source_matchers: ['severity="critical"', 'alertname="NodeDown"']
target_matchers: ['severity=~"warning|info"']
equal: ["node"]
- source_matchers: ['alertname="DatabasePrimaryDown"']
target_matchers: ['alertname=~"ServiceDependencyTimeout|DBConnectionFailed"']
equal: ["cluster"]
4.3 基于 SLO 的告警
阈值型告警(CPU > 80%)的最大问题是「与用户影响脱钩」。基于 SLO 的告警直接用「错误预算燃烧速率」触发,天然只在对用户有影响时响。
# 多窗口燃烧率告警(快速燃烧 + 慢速燃烧)
groups:
- name: slo-burn-rate
rules:
- alert: ErrorBudgetBurnFast
expr: |
(sum(rate(http_requests_total{status=~"5.."}[5m])) by (job)
/ sum(rate(http_requests_total[5m])) by (job)) > (14.4 * 0.001)
and
(sum(rate(http_requests_total{status=~"5.."}[1h])) by (job)
/ sum(rate(http_requests_total[1h])) by (job)) > (14.4 * 0.001)
for: 2m
labels: { severity: critical }
annotations:
summary: "{{ $labels.job }} 错误预算快速燃烧"
runbook_url: "https://runbooks.internal/burn-rate"
SLO 与错误预算的完整推导可参考 SLO 与错误预算 ,告警规则与通知渠道的工程细节(分组、静默、路由)与本文的降噪策略互补。
4.4 阈值告警的定位
阈值告警不是不能用,而是要改变定位:
症状型告警(SLO/可用性)→ 触发呼叫,因为用户受影响
原因型告警(CPU/内存/磁盘)→ 只进仪表盘或 IM,供诊断用
判断一条告警该不该呼叫,问一句:
「用户现在受影响了吗?」——是则呼叫,否则不呼叫。
5. 可操作性与 Runbook 绑定
5.1 告警必须可操作
一条合格的告警通知应包含:
1. 是什么:告警名 + 一句话描述
2. 影响:哪个服务、哪个区域、影响多少用户
3. 证据:关键指标链接(仪表盘、日志查询)
4. 动作:第一件事做什么(Runbook 链接)
5. 升级:多久未解决该找谁
缺失 3、4、5 的告警 = 不可操作 = 噪音。
5.2 告警与 Runbook 绑定
annotations:
summary: "订单服务 P99 延迟超过 2s"
description: "{{ $labels.job }} 在 {{ $labels.region }} 的 P99 达到 {{ $value }}s"
dashboard_url: "https://grafana.internal/d/order-svc"
runbook_url: "https://runbooks.internal/order-latency"
escalation: "30 分钟未恢复,联系 order-platform"
Runbook 的编写与自动化(Runbook as Code、自愈脚本)可参考 运维自动化与 Runbook as Code ——当同一告警反复出现且处置步骤固定时,就应该把它自动化掉,而不是反复人工处理。
5.3 告警评审机制
定期评审(每两周一次):
1. 列出本周期所有告警,按「是否可操作」分类
2. 不可操作的告警:要么删除,要么改造成可操作
3. 反复出现但无需人工的告警:自动化或降级为信息
4. 从未触发过的告警:检查是否失效(阈值过松或指标断流)
5. 记录每条告警的处置时长,识别「卡住」的环节
6. 交接与复盘
6.1 班次交接
交接清单(每次换班必过):
□ 当前未关闭的告警与事故
□ 进行中的变更/发布
□ 已知的脆弱点(如某节点磁盘告警中)
□ 需要跟进的事项(临时缓解措施、待观察项)
□ 环境异常(如监控采集有缺口)
# 生成交接摘要(示意:从 PagerDuty API 拉取本班次数据)
curl -s -H "Authorization: Token $PD_TOKEN" \
"https://api.pagerduty.com/incidents?since=$(date -u -v-12H +%Y-%m-%dT%H:%M:%SZ)&statuses[]=triggered&statuses[]=acknowledged" \
| jq -r '.incidents[] | "\(.created_at) [\(.urgency)] \(.title)"'
6.2 复盘与改进
复盘(Postmortem)的核心不是「谁错了」,而是「系统哪里该改」:
- 时间线:从第一个信号到完全恢复的每一步
- 根因:技术根因 + 组织/流程根因
- 改进项:每条改进项要有负责人与到期日
- 告警质量:本次事故中,告警是「太晚」还是「太多」?
告警质量的三个反思问题:
1. 用户受影响多久后我们才知道?(MTTD 是否合格)
2. 有没有误报/重复告警干扰?(噪音是否掩盖了信号)
3. 处置时缺了什么信息/权限?(可操作性是否足够)
无责备文化是复盘有效的前提,这一点在 SRE 的组织实践中已有系统总结。
7. 度量与常见坑
7.1 值班健康度量
告警量类:
- 每班次打扰型告警数(目标 < 2)
- 误报率(目标 < 20%)
- 夜间告警占比(目标 < 10%)
响应类:
- 告警确认时长(ack time)
- MTTD(Mean Time To Detect):从故障发生到告警触发
- MTTR(Mean Time To Repair):从告警到恢复
健康类:
- 值班人满意度(定期问卷)
- 值班导致的次日产出下降(间接度量)
- 因告警疲劳导致的漏响应次数
7.2 常见坑
| 坑 | 现象 | 对策 |
|---|---|---|
| 阈值告警泛滥 | 噪音淹没信号 | 症状型呼叫、原因型进面板 |
| 无分级 | 重要告警被稀释 | P1~P4 分级 + 分流通道 |
| 无抑制 | 级联告警爆炸 | 抑制规则 + 关联 |
| 告警不可操作 | 收到不知做什么 | 绑定 dashboard 与 runbook |
| 无升级机制 | 告警无人响应 | 未确认自动升级 |
| 值班人数不足 | 轮换过密,劝退 | ≥ 4 人 + 主备 + 影子 |
| 无交接 | 上下文丢失 | 标准化交接清单 |
| 复盘无跟踪 | 改进项烂尾 | 改进项带负责人与到期日 |
| 无度量 | 退化无人知 | 上报告警量与误报率 |
7.3 一句话原则
值班工程的目标 = 让「被叫醒」这件事重新变得有意义。
降噪到可处理、分级到准确、告警到可操作、复盘到有改进。
小结
值班不是排班表,而是一套需要设计的系统。治理告警疲劳的核心动作有四步:先降噪(去重、聚合、抑制,把量压到人可处理的水平)、再分级(按用户影响分级并分流到呼叫/IM/归档通道)、然后可操作(每条告警绑定仪表盘与 Runbook)、最后闭环(交接、复盘、度量,持续改进)。
衡量这套系统是否健康,看四个数就够了:每班次打扰型告警数、误报率、夜间告警占比、MTTD。当值班从「天天被吵醒、大部分是误报」变成「偶尔被叫醒、每次都真有大事」,团队才真正有了可靠的运营底座。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。