为自己代码值班 — 可持续的待命体系与事故学习
为自己代码值班 — 可持续的待命体系与事故学习
这一章讲什么: 「你写的东西你背」落到日常,就是值班表、告警、runbook、 复盘会这一整套具体的东西。本章把「开发者背线上」从口号拆成可操作的零件: 轮班怎么排才不把人耗干,告警怎么调才不会被当成狼来了,半夜出事按什么步骤查, 第二天复盘怎么开才真的让同类事故不再发生。
1. 主线例子:凌晨两点的一次告警,从响到复盘
本章的主线例子,是一次完整的事故生命周期。
02:07 手机响:PagerDuty 推送——
「payment-api 错误率 > 5% 持续 2 分钟【critical】
附:服务、环境、指标曲线链接、相关仪表盘」
02:08 你打开 runbook(表 12.2 的七段结构),按症状索引:
「API 返回 5xx → 可能原因:数据库连接问题/证书过期
→ 立即动作:kubectl rollout restart deployment payment-api」
02:12 服务恢复,runbook 回滚预案没用上;你在值班频道留了时间线
02:30 继续睡
次日 用结构化日志按 trace_id 串起全链,发现根因:
一个下游欺诈检查 API 超时,correlation ID 显示 80% 的延迟耗在那里
→ 自定义指标 payment_success_rate 加一条按区域的分维度
48 小时内 无指责复盘会:五连问追到「客户端重试没配限速」,
行动两项(加重试上限、加队列长度告警),有负责人有截止日期
下季度 同类事故不再出现;MTTR 因为这轮改进又降了一点
图说:一次告警的完整价值 = 当晚恢复(分钟级)
+ 次日根因(结构化日志 + trace)+ 季度免疫(复盘行动项)。
时间点与流程沿原书 runbook/复盘结构;错误率阈值等数值沿原书示例。下面五节展开:§2 为什么开发者该背线上,§3 值班体系怎么排,§4 用设计压 MTTR, §5 日志与自定义指标怎么为值班服务,§6 复盘怎么开才有用。
2. 为什么开发者该背线上
传统分工的边界——「写代码」与「跑代码」两群人——在分布式时代撑不住了: 出事时开发说「我机器上好好的」,运维对着看不懂的代码干瞪眼,互相甩锅、恢复变慢。 DevOps 给出的统一原则还是那句:you build it, you run it1。
背线上的真正价值是闭环:认证服务在大流量下偶发失败,背值班的开发者会亲眼看到 生产日志里那个未处理的异常和低效的数据库调用——感受过故障疼痛的开发者, 比只读过事故报告的开发者更可能写出有韧性的系统2。Netflix、Google、Amazon 都是把告警责任分给离服务最近的工程师,而不是集中 NOC; Google SRE 的研究口径:开发者参与轮班的团队事故恢复快 35%,生产引入的 bug 更少3。
三个常见误解的澄清(原书)4:「开发者不该碰运维」——懂生产行为恰恰提升开发能力; 「会 burnout」——burnout 来自糟糕的值班设计,不来自 ownership 本身; 「运维专家会失业」——他们进化成平台工程(造自动化、可观测与护栏的人)。
度量 ownership 的五个指标(原书表 12.1):MTTD、MTTR、错误预算、 部署频率、变更失败率5。
案例(金融科技公司,原书数字):运维团队单独 triage 的时代,每个问题都要 事后拉开发者;2023 年改成产品团队自己轮班、配 PagerDuty/Grafana/Loki 培训、 授权受控回滚——MTTD 降 45%,平均解决时长 90 → 25 分钟,重复事故降 30%, 开发者满意度反而上升6。
3. 值班体系:轮班、告警、runbook、交接、防耗
好值班体系的三原则:可靠(告警必达、升级路径清晰)、 可持续(负担均分、非行动告警要少)、透明(谁值班、怎么升级、该做什么,人人可查)7。
3.1 四种轮班模型
| 模型 | 结构 | 适用 |
|---|---|---|
| 单层轮班 | 全员平等,每人固定一周 | 小团队 |
| 多层轮班 | 一线响应 → 二线支援 → 三线(资深/SRE/经理) | 中大型团队 |
| 跟太阳走 | 亚太→欧洲→北美按工作时间接力,无人半夜被叫 | 全球分布团队 |
| 按服务分队 | 每个微服务由 owning 团队轮值 | 微服务多的组织(原书例子:50 个服务分 10 个队,每人每月亮一周) |
3.2 告警治理:精确率就是生命线
告警疲劳(alert fatigue)是值班体系的头号杀手:太多、太含糊的告警最终都会被忽略。 治理五条8:
- 阈值要挑「持续的异常」——「CPU > 85% 持续 5 分钟」而不是每次小抖动;
- 每条告警带上下文:服务、环境、指标、仪表盘链接;
- 分级:critical / high / medium / low;
- 限流与去重:同源多告警合并成一个事件;
- 定期评审告警规则,跟着系统行为进化。
案例(零售平台,原书数字):API 延迟告警阈值过激、误报不断; 改成「连续两分钟 5xx 或延迟超 500ms 才触发」——误报降 60%9。
3.3 Runbook:七段结构
事故里每秒都贵,没时间现场查资料。Runbook(操作手册)按症状索引,
七段结构(原书表 12.2):服务名 → 症状 → 可能原因 → 立即动作(具体命令)→
诊断步骤 → 升级联系人(「10 分钟未解决找二线某某」)→ 回滚预案
(helm rollback auth-api 42)10。
3.4 交接与防 burnout
交接四件:进行中的事故摘要、监控与工单状态更新、固定频道沟通、 升级与临时修复全部留痕(PagerDuty 可自动生成班次报告)11。
防耗五条12:轮班以周为单位且周末能休;半夜处理完事故的人早上不该照常上班; 高强度周后给补休;公开认可值班贡献;用脚本机器人吃掉重复低风险告警。 盯一个数:每人每周可行动告警均值持续超过 5–7 条,就该调阈值或修系统。 案例(流媒体公司,原书数字):跟太阳走 + 告警去重后,非工作时间告警降 40%, 满意度升 25%13。
4. 用设计压 MTTR:让系统自己修自己
MTTR(平均恢复时长)的账要从事故发生前算起。原书的立场一句话: 目标不只是更快地修,是设计出能自己修自己的系统14。
五个 proactive 原则15:为故障而设计(支付网关挂了先排队交易而不是直接拒单)、 自动化检测(健康检查/合成监控/异常检测,别等用户报障)、 自愈(K8s 探针重启容器、自动扩缩、数据库多可用区 failover)、 回滚简化(金丝雀/蓝绿,一键回)、可观测性嵌入(排障时间大头是诊断,不是修)。
告警关联:高 MTTR 的隐形推手是告警风暴——同一 Pod 引发延迟、5xx、内存 三条独立告警,关联引擎应合成一个根因告警(New Relic/Dynatrace/Datadog 用 ML 做)16。
四个自动修复机制17:健康探针与重启策略;自动扩缩容;自动 failover (RDS/Cloud SQL 跨可用区);runbook 自动化(StackStorm/Rundeck 把 常见处置变成脚本)。案例(SaaS 分析平台,原书数字):探针 + 恢复策略上线后, MTTR 40 → 5 分钟,70% 的事故无需人工18。
降低 MTTR 的五个设计模式(原书表 12.3):熔断器、优雅降级、 不可变基础设施(修不如换,回滚即换新)、特性开关(不重新部署就能关功能)、 混沌工程19。
案例(数字银行,原书数字):自动扩缩 + 自定义指标 + 告警关联 + runbook 自动化 + 自愈探针——MTTR 42 → 7 分钟,60% 事故自动解决20。 持续改进五步:按月追 MTTR 趋势 → 按因分类(代码/基础设施/配置/第三方)→ 重复问题自动化 → 简化手工步骤 → 复盘结论回流设计21。
判断(我们的,不是书里的): 本章所有自动化里,告警关联是被低估最深的: 它不改变任何系统行为,只改变「到达人眼前的信息量」。 一个常见模式是:MTTR 降不下来,团队归因于「诊断慢」,于是加日志加指标—— 结果信息更多,告警更多,MTTR 反而升。先收敛信号(关联、去重、分级), 再扩充信号(更多指标),顺序反了就是在给疲劳的值班者加噪。 如果错,会错在: 根因定位 AI(直接给故障定位建议)成熟后, 「收敛信号」这层可以由机器代劳,人工先看结论再看原始告警; 但那要求告警数据本身结构化良好——关联与分级的纪律依然是地基。
5. 为值班服务的日志与指标
监控答「有没有问题」,可观测性答「为什么有问题」22。
结构化日志(structured logging):JSON 键值对,三优势——一致性(固定 schema 可自动分析)、 可过滤(按 service="payment-api" 或 status_code=500 查询)、可关联 (带 trace_id/request_id)。对照例子(照原书表 12.4):一行自由文本 「Error: Payment service timeout while processing order #7841」vs 一条 JSON 含 timestamp/level/service/order_id/error/duration_ms/trace_id—— 后者可以按字段查,而不是按运气翻23。
日志级别五级(DEBUG/INFO/WARNING/ERROR/CRITICAL,原书表 12.5), 按环境动态调:预发 DEBUG、生产 ERROR24。
Correlation ID:请求入口生成唯一 ID,穿透所有下游调用、写进每条日志; 配上 Jaeger/OTel,一次 trace 可能揭示 80% 的延迟根本不在你的服务, 而在下游欺诈检查 API——这是传统日志永远给不出的视角25。
自定义业务指标(原书例子,名字照抄):auth_failures_total(每分钟登录失败)、
orders_value_avg(每小时平均订单额)、queue_processing_time_seconds、
payment_success_rate(按区域)——告警挂在业务影响上,而不是通用基础设施阈值上26。
集成五条:跨服务字段名统一、粒度得当(不记敏感数据)、指标加区域/版本标签、 集中存储单一工具栈、可观测性管道当代码测(预发验证关键信号真的被采集)27。
案例(流媒体平台,原书数字):结构化日志 + 自定义指标 + OTel 追踪后, 一次故障靠 trace 发现 70% 失败会话源自一个区域边缘缓存配置错,10 分钟修复; MTTR 整体降 50%28。
6. 复盘:把事故变成资产
事故不可避免;高绩效团队的标志是从事故里学到多少。复盘(postmortem, 名字借自医学「死后检验」)抓根因、评估响应、定预防措施、沉淀知识29。
无指责文化是前提(谷歌 SRE 手册带火的实践):四个原则—— 问系统为什么允许错误发生,不问谁犯了错(「为什么告警被漏了?」而不是「谁忽略了告警?」); 人人敢讲;只记事实(时间戳、日志),不写情绪;落点是改进不是追责30。 追责的代价是真实的:人会藏信息、瞒险情。
报告结构九段(原书表 12.6):事故 ID → 时间与持续时长 → 影响摘要 → 根因分析 → 事件时间线 → 解决细节 → 加剧因素(什么拖慢了恢复)→ 经验教训 → 行动项与负责人(具体、可度量、有截止日期)31。
流程七步32:解决后 24–72 小时内开(记忆最新鲜)→ 全员参与(开发/SRE/QA/产品)→ 用日志和聊天记录重建分钟级时间线 → 五连问(Five Whys)逐层追问: 网关崩了 → 为什么?内存耗尽 → 为什么?请求队列失控 → 为什么? 客户端重试循环配置错 → 为什么?配置文件缺限速逻辑—— 第五个为什么通常挖到流程与设计的洞 → 图表化记录 → 行动项到人到期 → 全组织公开(Confluence/wiki)。
SEV 分级:SEV-1 全面复盘,SEV-2 结构化分析,SEV-3 迷你复盘33。 五个坑:走过场填模板;行动项不跟(重复事故保证来);只盯技术原因忽视流程; 不跨团队分享;语气带指责34。
案例(金融科技初创,原书数字):2024 年中起正式无指责复盘, 一次复盘揪出「API 限速器没随流量扩容」的根因,并顺手把容量测试脚本塞进 CI、 按流量模式调了告警阈值——三个月 SEV-1 降 40%, 开发者开始在部署前主动讨论可能的故障场景35。
学习的最后一步是回流:更新 runbook、把手工缓解写成自动化护栏、 调整监控、行动项进 sprint backlog、定期回看同类事故是否真的减少36。
7. 边界与局限
- 值班补偿与劳动制度完全没提:补休、加班费、轮班津贴在不同法域差别巨大, 这恰是「可持续」最硬的一层约束。
- 「Google 研究:参与轮班恢复快 35%」没有给出处,引用时注明是书中转述。
- 五连问有方法论缺陷(单线因果、停在某个为什么上),更系统的 事故分析(如鱼骨图、多重因果)没有提。
- runbook 与自动化的关系讲得浅:什么该留在人肉 runbook、什么该脚本化, 判据没给(第 11 章的「resilience as code」补了一点)。
- 案例数字均无出处。
8. 可带走的
- 背线上是反馈装置:疼过的开发者才写防御性代码;三个误解(碰运维/ burnout/ 运维失业)都不成立;
- 值班三原则:可靠、可持续、透明;四种模型按团队规模和时区选;
- 告警治理五条的命门是误报率——告警被信任比告警多重要;
- Runbook 七段,按症状索引,具体命令 + 升级时限 + 回滚预案;
- 防 burnout 盯一个数:人均每周可行动告警别长期超 5–7 条;
- MTTR 的账在事故前算:自愈、自动 failover、一键回滚、runbook 自动化;
- 先收敛告警(关联去重分级)再扩充信号——顺序反了就是加噪;
- 结构化日志 + correlation ID + 业务自定义指标 = 值班者的三件套;
- 复盘无指责、24–72 小时内开、五连问到流程层、行动项到人到期、全组织公开;
- 复盘的产出必须回流:runbook、护栏、监控、backlog——闭环才算数。
9. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| you build it you run it、35% 研究 | Introduction(第 12 章) | text/40-fm-introduction.txt:64(搜「You build it, you run it」) · text/40-fm-introduction.txt:114(搜「35%」) |
| 三误解与五个 ownership 指标 | Introduction(第 12 章) | text/40-fm-introduction.txt:124(搜「should not be bothered」) · text/40-fm-introduction.txt:286(搜「Table 12.1」) |
| 金融科技值班案例 | Introduction(第 12 章) | text/40-fm-introduction.txt:140(搜「real-time payment」) · text/40-fm-introduction.txt:153(搜「90 minutes」) |
| 值班三原则与四种轮班 | Introduction(第 12 章) | text/40-fm-introduction.txt:334(搜「Reliability」) · text/40-fm-introduction.txt:357(搜「Primary on-call」) · text/40-fm-introduction.txt:366(搜「Follow-the-sun」) |
| 告警治理与误报 -60% | Introduction(第 12 章) | text/40-fm-introduction.txt:386(搜「85%」) · text/40-fm-introduction.txt:408(搜「60%」) |
| Runbook 七段 | Introduction(第 12 章) | text/40-fm-introduction.txt:417(搜「step-by-step」) · text/40-fm-introduction.txt:485(搜「rollout restart」) · text/40-fm-introduction.txt:532(搜「Table 12.2」) |
| 防 burnout 五条与流媒体案例 | Introduction(第 12 章) | text/40-fm-introduction.txt:568(搜「Weekly rotations」) · text/40-fm-introduction.txt:583(搜「5 to 7」) · text/40-fm-introduction.txt:587(搜「40%」) |
| 主动 MTTR 五原则与四机制 | Introduction(第 12 章) | text/40-fm-introduction.txt:641(搜「Design for failure」) · text/40-fm-introduction.txt:690(搜「liveness」) · text/40-fm-introduction.txt:703(搜「40 minutes」) |
| MTTR 设计模式表与银行案例 | Introduction(第 12 章) | text/40-fm-introduction.txt:855(搜「Table 12.3」) · text/40-fm-introduction.txt:887(搜「42 minutes」) |
| 结构化日志对照与 correlation ID | Introduction(第 12 章) | text/40-fm-introduction.txt:1008(搜「8f29d4」) · text/40-fm-introduction.txt:1169(搜「uuid.uuid4」) · text/40-fm-introduction.txt:1190(搜「80% of total latency」) |
| 自定义指标与集成五条 | Introduction(第 12 章) | text/40-fm-introduction.txt:1203(搜「auth_failures_total」) · text/40-fm-introduction.txt:1265(搜「Standardize formats」) |
| 无指责四原则与五连问 | Introduction(第 12 章) | text/40-fm-introduction.txt:1344(搜「Focus on systems」) · text/40-fm-introduction.txt:1534(搜「The API gateway crashed」) |
| 报告九段与七步流程 | Introduction(第 12 章) | text/40-fm-introduction.txt:1504(搜「Table 12.6」) · text/40-fm-introduction.txt:1519(搜「24 to 72 hours」) |
| SEV 分级与五个坑 | Introduction(第 12 章) | text/40-fm-introduction.txt:1577(搜「SEV-1」) · text/40-fm-introduction.txt:1597(搜「formalities」) |
| 金融科技复盘案例(-40%) | Introduction(第 12 章) | text/40-fm-introduction.txt:1622(搜「60-minute debrief」) · text/40-fm-introduction.txt:1628(搜「40%」) |
Footnotes
-
出处:「Introduction」(第 12 章)第 64 段(
text/40-fm-introduction.txt:64,搜「You build it, you run it」)。 ↩ -
出处:「Introduction」(第 12 章)第 73–76 段(
text/40-fm-introduction.txt:76,搜「feels the pain」)。 ↩ -
出处:「Introduction」(第 12 章)第 85 段(
text/40-fm-introduction.txt:85,搜「Netflix, Google, and Amazon」)与第 114 段(text/40-fm-introduction.txt:114,搜「35% faster recovery」)。注:该研究数字原书未给出处。 ↩ -
出处:「Introduction」(第 12 章)第 124–134 段(
text/40-fm-introduction.txt:124,搜「should not be bothered」)。 ↩ -
出处:「Introduction」(第 12 章)第 163–286 段(
text/40-fm-introduction.txt:286,搜「Table 12.1」)。 ↩ -
出处:「Introduction」(第 12 章)第 137–160 段(
text/40-fm-introduction.txt:153,搜「90 minutes」;text/40-fm-introduction.txt:150,搜「45%」)。 ↩ -
出处:「Introduction」(第 12 章)第 327–344 段(
text/40-fm-introduction.txt:334,搜「Reliability」;text/40-fm-introduction.txt:337,搜「Sustainability」)。 ↩ -
出处:「Introduction」(第 12 章)第 379–405 段(
text/40-fm-introduction.txt:386,搜「85%」;text/40-fm-introduction.txt:401,搜「deduplication」)。 ↩ -
出处:「Introduction」(第 12 章)第 408 段(
text/40-fm-introduction.txt:408,搜「60%」)。 ↩ -
出处:「Introduction」(第 12 章)第 417–535 段(
text/40-fm-introduction.txt:485,搜「rollout restart」;text/40-fm-introduction.txt:524,搜「helm rollback」)。 ↩ -
出处:「Introduction」(第 12 章)第 541–558 段(
text/40-fm-introduction.txt:558,搜「end-of-shift reports」)。 ↩ -
出处:「Introduction」(第 12 章)第 561–583 段(
text/40-fm-introduction.txt:583,搜「5 to 7」)。 ↩ -
出处:「Introduction」(第 12 章)第 587 段(
text/40-fm-introduction.txt:587,搜「40%」)。 ↩ -
出处:「Introduction」(第 12 章)第 602–608 段(
text/40-fm-introduction.txt:608,搜「fix themselves」)。 ↩ -
出处:「Introduction」(第 12 章)第 631–653 段(
text/40-fm-introduction.txt:641,搜「Design for failure」)。 ↩ -
出处:「Introduction」(第 12 章)第 657–679 段(
text/40-fm-introduction.txt:663,搜「root-cause alert」)。 ↩ -
出处:「Introduction」(第 12 章)第 683–703 段(
text/40-fm-introduction.txt:690,搜「liveness」;text/40-fm-introduction.txt:699,搜「StackStorm」)。 ↩ -
出处:「Introduction」(第 12 章)第 703 段(
text/40-fm-introduction.txt:703,搜「40 minutes」)。 ↩ -
出处:「Introduction」(第 12 章)第 732–855 段(
text/40-fm-introduction.txt:855,搜「Table 12.3」)。 ↩ -
出处:「Introduction」(第 12 章)第 861–887 段(
text/40-fm-introduction.txt:887,搜「42 minutes」)。 ↩ -
出处:「Introduction」(第 12 章)第 890–911 段(
text/40-fm-introduction.txt:896,搜「Track MTTR trends」)。 ↩ -
出处:「Introduction」(第 12 章)第 926 段(
text/40-fm-introduction.txt:926,搜「Why is it wrong」)。 ↩ -
出处:「Introduction」(第 12 章)第 966–1016 段(
text/40-fm-introduction.txt:1008,搜「8f29d4」;text/40-fm-introduction.txt:1016,搜「Table 12.4」)。 ↩ -
出处:「Introduction」(第 12 章)第 1025–1148 段(
text/40-fm-introduction.txt:1148,搜「DEBUG in staging」)。 ↩ -
出处:「Introduction」(第 12 章)第 1151–1190 段(
text/40-fm-introduction.txt:1169,搜「uuid.uuid4」;text/40-fm-introduction.txt:1190,搜「80% of total latency」)。 ↩ -
出处:「Introduction」(第 12 章)第 1193–1255 段(
text/40-fm-introduction.txt:1203,搜「auth_failures_total」)。 ↩ -
出处:「Introduction」(第 12 章)第 1258–1280 段(
text/40-fm-introduction.txt:1265,搜「Standardize formats」;text/40-fm-introduction.txt:1280,搜「Treat logging」)。 ↩ -
出处:「Introduction」(第 12 章)第 1284–1293 段(
text/40-fm-introduction.txt:1290,搜「70%」;text/40-fm-introduction.txt:1293,搜「50%」)。 ↩ -
出处:「Introduction」(第 12 章)第 1296–1331 段(
text/40-fm-introduction.txt:1318,搜「root causes」)。 ↩ -
出处:「Introduction」(第 12 章)第 1334–1357 段(
text/40-fm-introduction.txt:1344,搜「Focus on systems」;text/40-fm-introduction.txt:1357,搜「SRE handbook」)。 ↩ -
出处:「Introduction」(第 12 章)第 1360–1504 段(
text/40-fm-introduction.txt:1504,搜「Table 12.6」)。 ↩ -
出处:「Introduction」(第 12 章)第 1510–1564 段(
text/40-fm-introduction.txt:1519,搜「24 to 72 hours」;text/40-fm-introduction.txt:1528,搜「Five Whys」;text/40-fm-introduction.txt:1549,搜「process or design flaw」)。 ↩ -
出处:「Introduction」(第 12 章)第 1567–1587 段(
text/40-fm-introduction.txt:1577,搜「SEV-1」)。 ↩ -
出处:「Introduction」(第 12 章)第 1590–1613 段(
text/40-fm-introduction.txt:1600,搜「Skipping follow-ups」)。 ↩ -
出处:「Introduction」(第 12 章)第 1616–1628 段(
text/40-fm-introduction.txt:1628,搜「40%」)。 ↩ -
出处:「Introduction」(第 12 章)第 1631–1657 段(
text/40-fm-introduction.txt:1657,搜「self-correcting systems」)。 ↩