09 On-Call 值班
概述#
On-call 是 SRE 工作中最直接影响工程师生活质量的部分。Google SRE Book 里有明确约束:SRE 的 on-call 工作量不能超过总时间的 25%。这不是福利,是工程要求——超了就说明告警治理、自动化、责任共担出了问题。
On-call 的本质不是"被人叫醒处理告警",而是"系统在非工作时间仍有可靠的人工兜底"。一个健康的 on-call 体系,应该让值班人能在被叫醒时高效处置、能在不被叫醒时安心睡觉、能在轮值结束后真正恢复。
本章从轮值制度设计到交接 SOP 到心理负荷管理,建立一套可持续的值班体系。大量实践经验来自 On-Call 轮值管理实战。
一、轮值制度设计#
三种主流轮值方式#
| 方式 | 描述 | 优点 | 缺点 |
|---|---|---|---|
| 每周轮值 | 周一~周日 7 天 | 交接少,节奏统一 | 周末剥夺感大 |
| 每日轮值 | 24 小时一轮 | 恢复快 | 交接频繁(每次交接都是风险点) |
| 工作日+周末分开 | 工作日一人,周末另一人 | 最人性化 | 需要更多人手 |
| 白天+夜晚分开(follow-the-sun) | 跨时区轮值 | 无夜间告警 | 需要多地办公室 |
推荐方案:工作日 + 周末分开值班。周末值班给 1.5 倍补偿(调休或薪酬)。实测团队满意度最高。
团队规模与频率#
| 团队规模 | 每人年 on-call 周数 | 体感 |
|---|---|---|
| 4 人 | 13 周 | 疲惫(不建议) |
| 5-6 人 | 8-10 周 | 有压力但可承受 |
| 7-8 人 | 6-7 周 | 较健康(最佳区间) |
| 9+ 人 | < 6 周 | 脱手严重,不熟悉系统 |
最佳区间是 6-8 人。4 人以下建议和隔壁团队合并。9 人以上建议拆成两个 rotation——人太多导致每个人轮值间隔过长,对系统生疏。
补偿机制#
On-call 必须有显性补偿:
| 情景 | 补偿 |
|---|---|
| 工作日 on-call | 1 天调休/班次 |
| 周末 on-call | 2 天调休/班次 |
| 夜间被叫醒(22:00-8:00) | 额外 0.5 天调休 |
| 处理 SEV-1/2 超过 2 小时 | 计入加班 |
调休关键:允许在下一个 sprint 灵活消化,不能强制"当天补休"——否则 on-call 后的白天不休息也得干活,等于没补。
补偿不是福利,是工程要求。没有补偿的 on-call 不可持续——工程师会在 1-2 年内离职,带走所有系统知识。Google 的数据:on-call 补偿到位的团队,工程师平均在职时间 4.2 年;没有补偿的团队,平均 1.8 年。
不补偿的代价#
一个真实案例(来自 On-Call 实战文章):
一位很敬重的工程师在离职面谈里说:「我离职不是因为工资,也不是因为项目。是因为连续三个月每周被深夜 4 点叫醒,我老婆说再这样下去她要带孩子回娘家。我没法继续了。」
这位工程师离职后,团队失去了一个对系统最熟悉的人,bus factor 从 2 降到 1。后续 6 个月里发生了 3 次本来他能避免的事故——这就是不补偿的真实代价。
二、响应时间分级#
告警分级与响应 SLA#
| 级别 | 响应要求(Ack) | 处理要求 | 通道 |
|---|---|---|---|
| P0 Critical | 5 分钟内 | 立即响应,15 分钟 mitigation | 电话 + 钉钉 |
| P1 Warning | 15 分钟内 | 1 小时内开始处理 | 钉钉 |
| P2 Info | 下个工作日 | 排期处理 | 工单 |
Ack ≠ 处理完成。Ack 只是"我看到了,开始响应"。如果值班人 5 分钟不 ack,系统应自动升级。
为什么 Ack 和处理要分开#
事故响应有几个关键时间点:
- TTD(Time to Detect):从故障发生到告警触发
- TTA(Time to Acknowledge):从告警触发到值班人确认
- TTM(Time to Mitigate):从 ack 到服务恢复
- TTR(Time to Resolve):从告警到事故完全关闭
故障发生 ─── TTD ─── 告警 ─── TTA ─── Ack ─── TTM ─── Mitigated ─── TTR ─── ResolvedAck 单独衡量是因为它反映"值班人是否可靠"。TTA 过长通常不是技术问题,是值班制度问题——值班人睡着了、手机静音了、网络断了。
升级链(Escalation Policy)#
Level 1 (0~5min) : primary on-call
Level 2 (5~10min) : secondary on-call
Level 3 (10~15min): team lead
Level 4 (15+min) : IMOC / manager on duty关键规则:
- primary 5 分钟不 ack,自动升级到 secondary
- secondary 只在 primary 失联时顶上,不每个告警都叫两个人
- 升级到 team lead 不是惩罚 primary,是流程的一部分
- 升级不等于替代,primary 依然负责事故
- 3 层足够,再多让 primary 产生依赖心理
Secondary 的设计#
- 不会被每个告警打扰,只在 primary 未 ack 时
- 可以比 primary 更低资历(如 L3 工程师配 L5 secondary)
- 周期和 primary 错开一周,避免两人同时疲劳
- secondary 也要被调度,但负担比 primary 小
不要让一个人扛#
最差的做法是"只有一个人被 page"。任何 SEV-2 以上,primary 应该主动拉 secondary 上线,不要死撑。明确告诉每个 on-call:你觉得扛不住就叫人,这不是软弱,是流程。
三、交接 SOP#
交接是 on-call 最常被忽视的环节。糟糕的交接让新 on-call 的第一小时在猜谜。
交接清单模板#
## On-Call Handoff: <from> -> <to>
### 日期
2026-07-01
### 待处理事项
- [ ] incident-2026-06-28-payment-api 还未写 postmortem
- [ ] 上周 OrderAPI_p99 告警调整的 Grafana dashboard
- [ ] ticket #1234 跟踪 MySQL SSL 证书续签
### 未解的根因
- Redis client 偶尔报 ETIMEDOUT(已压制,未定位)
- node-exporter 指标抖动,暂时放弃告警
### 环境变更
- 2026-06-30 Istio 从 1.21 升到 1.22
- 周四下午有一个新业务上线,sentinel 配额已预留
### 风险提醒
- MySQL 主库 SSL 证书 2026-07-05 过期,有 ticket #1234 跟进
- cert-manager 最近有异常重启,未定位
### Runbook 最近更新
- payment-api 的 rollback 步骤更新,新增 cache flush
- OrderAPI 的告警阈值调整说明交接流程#
- 交接会议 15 分钟,轮换日上午做
- 值班人员一对一过文档
- 所有内容归档到团队 wiki
- 交接文档模板标准化,不允许"自由发挥"
交接的常见问题#
- 口头交接没记录:3 天后双方都忘了说过什么
- 只说事没说背景:新 on-call 知道"Redis 有问题"但不知道"已经排查到哪一步"
- 风险提醒遗漏:证书快过期这种定时炸弹没说,新 on-call 完全不知道
- Runbook 更新没同步:老 on-call 改了 runbook 但没告诉新 on-call,处理时还在用旧步骤
四、心理负荷管理#
On-call 最大的问题往往不是技术,是心理——焦虑、怕出错、怕被追责。
建立心理安全#
- 显性 Blameless 文化:事故响应群追究的不是"谁做的",而是"怎么修复和防止再发"
- 公开承认 on-call 辛苦:管理层在会议上说"我知道最近告警多,辛苦你们"比任何补偿都有效
- 允许说"我不会":on-call 不是全能工程师,遇到不会的事应该升级
- 事故后关怀:经历大事故后值班人应有一天 recovery time,可以什么都不做
- On-call 表现不和绩效挂钩:处理得好不加分,处理不好不扣分——只看"是否按流程响应"
第 5 条争议最大。有人说"处理得好为什么不奖励"。答案是:on-call 是 team sport,个人英雄主义反而会让团队依赖个别人,长期看是负债。奖励个人会激励"独揽"行为,破坏团队协作。
告警疲劳度量#
不只是感觉,要数据:
# 每班次告警数
sum by(oncall_user) (increase(alertmanager_notifications_total{receiver="pager"}[7d]))
# 夜间告警占比
sum(increase(alertmanager_notifications_total{hour=~"22|23|0|1|2|3|4|5"}[30d]))
/ sum(increase(alertmanager_notifications_total[30d]))
# MTTA
avg(pd_incident_ack_time_seconds)
# 告警真阳率
count_over_time(incident_true_positive[30d])
/ count_over_time(incident_total[30d])健康指标参考:
- 每班次 page 告警:< 5 次
- 夜间告警比例:< 10%
- MTTA:< 5 分钟
- 真阳率:> 70%
On-Call 问卷调查(每季度)#
- 过去一个月你被夜间叫醒多少次?
- 1-10 分,你的 on-call 疲劳度?(1=轻松,10=崩溃)
- 最让你疲劳的三个告警是什么?
- 有没有告警你根本不知道怎么处理?
- Runbook 有没有漏洞?
- 你觉得当前轮值规则公平吗?
- 有没有什么事你一直想做但 on-call 吃掉了所有精力?
疲劳度 > 6 分时必须启动告警治理(见 Ch08),而不是让值班人继续硬扛。让疲劳度数据报给管理层——这比任何 PPT 都能说明问题。
心理负荷的隐性影响#
on-call 的心理负荷不只在"被叫醒"那一刻,还在"等待被叫醒"的状态:
- 周末不敢远离手机
- 晚上不敢深度睡眠
- 不敢安排长时间活动(看电影、出游)
- 持续的"会有告警"的焦虑
这种"待命焦虑"会持续消耗心力,即使没有被叫醒。长期下来导致:
- 睡眠质量下降
- 注意力分散
- 创造力下降(没法做深度工程)
- 家庭关系紧张
治理方法:
- 告警治理(最根本,减少告警数量)
- Secondary 兜底(primary 知道"我失联也有人接")
- 明确响应时间(5 分钟 ack,不是"立刻接电话")
- 心理健康支持(EAP 服务)
五、新人培养路径#
新同事加入 on-call rotation 不应该直接上岗:
Shadow 2 周 → 作为 observer 参与,不做操作,只观察
Shadowed 2 周 → 作为 primary 响应,资深工程师 shadow 随时接管
独立 + backup 2 周 → 独立处理,backup 随叫随到
完全独立 → 加入轮值表总共 6 周。时间长看起来慢,实际极大降低了新人的焦虑和误操作风险。
Shadow 阶段的细节#
- 跟着 primary 一起被叫醒,一起处理
- 不做任何操作,只观察
- 每次告警后和 primary 一起 review:为什么这样处理?
- 阅读 5-10 份历史 postmortem
Shadowed primary 阶段#
- 作为 primary 接告警
- 资深工程师在群里 shadow,随时准备接管
- 操作前必须经 shadow 确认
- 每次告警后 review:哪些操作是对的,哪些可以更好
独立 + backup 阶段#
- 独立处理告警
- backup 知道你在值班,可以求助
- 复杂事故(SEV-1/2)必须拉 backup
- 这阶段主要建立"独立决策"的信心
不要让新人独立扛 SEV-1#
新人独立 on-call 后的 3 个月内,SEV-1 事故必须有资深工程师协助。新人在高压下容易做错决策——这不是能力问题,是经验问题。
六、On-Call 工具栈#
告警分发#
- Alertmanager:开源,路由/分组/抑制/静默
- PagerDuty:商业,排班/升级/事件管理
- Grafana OnCall:开源 + 商业,和 Grafana 生态集成好
- OpsGenie:Atlassian 出品,和 Jira 集成
排班管理#
- PagerDuty / OpsGenie:原生排班功能
- 自研轮值表:Google Calendar / 钉钉机器人
- Grafana OnCall:开源排班
事件管理#
- incident.io / FireHydrant / Rootly:专业事件管理平台
- 自研 bot:500 行 Python 处理告警 routing + 值班查询 + 交接 reminder
工具选型建议#
- 小团队(< 10 人):Alertmanager + 自研轮值表就够
- 中团队(10-50 人):Alertmanager + Grafana OnCall 或 PagerDuty
- 大团队(50+ 人):必须用专业工具(PagerDuty / incident.io)
关键经验:不要一开始就上专业工具。先用 Confluence + 钉钉频道跑通流程,跑半年再决定是否买专业工具。专业工具主要省 20% 的操作,但 80% 的价值在你的流程和模板。
七、常见反模式#
| 反模式 | 问题 | 修正 |
|---|---|---|
| 一个人长期独揽 | 表面"他最懂",实际是组织脆弱性 | 强制轮值,bus factor > 1 |
| 告警越多越好 | 以为覆盖全,实际噪音压死信号 | 告警审计,砍到个位数/周 |
| primary+secondary 都响应 | 浪费两人时间 | secondary 只在 primary 失联时顶上 |
| on-call 完全不补偿 | 涸泽而渔 | 调休或加班费 |
| 升级链越来越长 | primary 产生依赖心理 | 3 层足够 |
| 把 on-call 当新人培训 | 新人扛不住会崩溃 | 先 shadow 再独立(6 周路径) |
| 交接走流程不走心 | 15 分钟会议变成 5 分钟念清单 | 一对一过文档,问答必答 |
| 告警 group 设得过大 | 合并 5 个独立告警成一条,丢失信号 | group_by 谨慎设置 |
| runbook 过时没人更新 | 改代码不改 runbook,下次值班人惨 | runbook 和代码同 PR |
| on-call 期间不能做其他事 | 太奢侈,小告警可以穿插处理 | 区分"待命"和"专注处理" |
八、On-Call 改革的实际案例#
来自 On-Call 实战文章的改革前后对比:
| 维度 | 改革前 | 改革后 |
|---|---|---|
| 团队规模 | 7 人 | 8 人 |
| 每周告警 | 28 次 | 6 次 |
| 夜间告警比例 | 29% | 8% |
| 每人年 on-call 周数 | 7.4 | 6.5 |
| 每人年被叫醒次数 | 59 | 4 |
| 告警真阳率 | 38% | 78% |
| on-call 疲劳度(问卷) | 7.2/10 | 3.8/10 |
| 季度主动离职 | 2 | 0 |
改革具体做了什么:
- 加 1 人到 rotation
- 告警清理(4 周专项)
- 工作日 / 周末拆开
- 交接 SOP 固化
- 夜间告警 escalation 补偿
- 每季度 toil survey
- team lead 每月 1:1 关注 on-call 状态
没有一项是"神奇技术",都是工程化的细节。
九、给管理层的话#
如果你是 engineering manager 或 director,记住一件事:on-call 不是团队的副产品,是核心交付能力。你对 on-call 的投入应该和对线上质量的投入成正比。具体:
- 把 on-call 质量指标(告警数、夜间比例、疲劳度)放进你的 monthly report
- 给团队一个明确的"on-call 优化"时间预算,每季度至少 5% 的工时
- 当 on-call 疲劳度高于 6 分时,把新 feature 优先级往后推
- 一个工程师离职时主动问"是不是 on-call 的原因"
- 给 on-call 值班人显性致谢,无论是所有人会议还是团队频道
这些不是"软技能",是让工程团队可持续的硬工程。
实战要点#
- 量化 on-call 质量:告警数、夜间比例、疲劳度必须变成数字,不能靠"感觉这周有点忙"。
- 告警审计是 on-call 治理的核心(见 Ch08 详细方法)。先砍噪音,再谈轮值优化。
- 补偿机制写在制度里,不靠口头承诺。口头承诺的补偿在人员变动后会失效。
- 交接文档必须存在。一个团队如果靠口头交接,on-call 质量不可能稳定。
- 新人培养走 6 周路径,不要让新人直接上岗。
- 心理安全比技术能力更重要——一个不敢升级的初级 on-call 比一个能力差的 on-call 危险得多。
- 管理层必须参与 on-call 治理——这不是"团队内部事务",是组织可靠性能力的一部分。
- 每季度做 toil survey,让数据说话,不要等问题爆发才处理。
小结#
On-call 最能暴露一个团队是靠工程还是靠英雄主义在扛。可持续的 on-call = 合理的轮值制度 + 持续的告警治理 + 显性的心理支持 + 规范化的交接流程。
判断一个团队 on-call 是否健康,看三件事:每周 page 告警 < 5 次、季度疲劳度 < 5 分、新人有 6 周培养路径。三件事都做到是健康体系;只做到一两件是"在改进中";一件都没做,on-call 就是"靠人扛"的不可持续状态。
下一章讲事件管理——on-call 接收到告警后的系统化响应。