严肃技术故障复盘与事故通报规范
事故复盘与故障通报不是“公关道歉信”,更不是“道德审判与甩锅大会”。它的唯一目的是:用不可辩驳的客观事实还原真相,把根因锁定在系统机制与物理约束的缺失上,并给出一经部署就不可绕过的物理防复发措施。
判断一份事故报告是否合格的唯一标准:读完之后,用户和工程师是觉得“这家公司在遮遮掩掩推卸责任”,还是清楚地知道“系统在哪个物理环节断了、这次教训换来了什么永久防线”?
零、事故通报六步骨架(The Postmortem Skeleton)
动笔撰写故障通报或技术复盘前,按此骨架填空,不缺步、不跳步:
① 首屏摘要 故障定级 · 影响范围(受损比例/脏数据行数/时长) · 核心根因一句话 ② 时间线 UTC 时间戳驱动 · 状态变化 · 发现/止血/根治的客观动作(零修辞) ③ 根因下钻 5 Whys 机制下钻 · 归因于机制缺失,绝不下钻到“某员工疏忽” ④ 止血处置 当时采取的应急措施 · 恢复线上可用的临时绕行方案 ⑤ 永久防线 Action Items · 谁主责 · 何时上线 · 依赖的物理门禁/代码约束 ⑥ 外部证据 监控图表 · 日志指纹 · Git Commit SHA · 外部健康探测回执
一、🚫 事故通报四大禁忌(Anti-PR Blacklist)
任何准备发给用户、客户或管理层的事故通报,严禁出现以下“公关八股”:
| 违规表述 | 为什么令人极其反感 | 工业级替代方案 |
|---|---|---|
| “给您带来的不便敬请谅解” | 万能无意义套话,用户受损时听到这话只觉冷漠与傲慢。 | 删掉!直接陈述补偿方案或已就绪的恢复动作(“受影响账单已全额回退,补偿配额已到账”)。 |
| “我们将深刻吸取教训,举一反三” | 语言的巨人、行动的矮子。没有任何工程落点。 | 给出代码级约束(“代码已引入 pre-commit 语法门禁,同类配置错误将在提交时被直接拒绝”)。 |
| “由于某工程师操作不当 / 某同事失误” | 把系统性漏洞甩给个人,暴露团队工程素养极差。 | 归因于防护机制缺失(“系统缺乏操作二次确认与沙箱隔离栅栏,允许未经验证的脚本直连了生产库”)。 |
| “极少数用户受到轻微影响” | 掩耳盗铃、试图粉饰太平,被抓出真实数据直接信誉破产。 | 给出精确客观数字(“共影响 142 个并发请求(占同时段总流量的 0.18%),持续 14 分钟”)。 |
二、关键段落表达规范
1. 影响面量化(Impact Scope)
- 绝不使用模糊字眼:禁止写“部分用户”、“短时间”、“个别接口”。
- 必须提供四维指标:
- 持续时长:起止时间点(精确到秒)。
- 受损流量比:5xx 错误请求数占总请求数的百分比。
- 业务受损量:失败的订单数、延迟的消息条数或受污染的数据库行数。
- 数据安全性确认:数据是否发生泄漏?是否发生不可逆丢失?(如无,明确声明“未发生数据丢失或越权泄漏”)。
2. 时间线还原(Timeline)
时间线必须是纯粹的事实流水账,每一个节点只包含两部分:时间戳 + 发生了什么。
text- 14:02:11 UTC:自动化部署任务 #412 开始向生产集群灰度推送 v2.4.1。 - 14:03:45 UTC:新加坡节点网络流量触发 502 警报,错误率升至 8.2%。 - 14:05:00 UTC:值班工程师接入,确认网关与数据库连接池打满。 - 14:07:30 UTC:执行一键回滚指令,切回 v2.4.0 镜像。 - 14:11:15 UTC:全节点流量恢复 200,监控指标回落至健康基线。
3. 根因下钻(Root Cause & 5 Whys)
下钻的终点必须是一个**“客观缺失的机制”,而不是一个“主观犯错的人”**。
text现象:线上网关发生 502。 Why 1: 为什么 502?因为数据库连接池耗尽,新请求被拒绝。 Why 2: 为什么连接池耗尽?因为迁移脚本 008 执行了一条全表关联的大查询。 Why 3: 为什么执行了大查询?因为缺少慢查询超时配置,单个事务挂起超过 60 秒。 Why 4: 为什么没有超时配置?因为上线前没有在 staging 环境执行生产级流量回放。 Why 5(根因): 系统缺乏自动化性能回归门禁,允许未经性能基准测试的 SQL 直接合入主干。
4. 永久性行动项(Action Items)
行动项必须遵循 SMART 原则,每一条必须有唯一负责人与截止时间,且必须是物理阻断机制(代码门禁、系统参数、定时巡检),不能是自觉要求。
| 改进方向 | 伪整改(自觉要求 ❌) | 真防线(物理机制 ✅) | 责任人 | 截止时间 |
|---|---|---|---|---|
| 数据库防护 | 要求大家以后写 SQL 注意加 limit | DB 网关强制配置 statement_timeout = 8s,超限自动掐断 | @vex | 2026-10-26 |
| 门禁拦截 | 提醒提单人不要漏写必填项 | CLI 引入字段校验器,缺块直接拒收 | @nanzhu | 2026-10-25 |
三、正反案例对比
❌ 假人公关推脱体
关于今日系统故障的情况说明
尊敬的用户:今日下午由于不可抗力的网络抖动及内部工作人员误操作,导致部分用户的系统访问受到轻微影响。故障发生后,我司技术团队高度重视,第一时间进行了紧急排查与修复,目前所有服务均已恢复正常。对此我们深表歉意,给您带来的不便敬请谅解!未来我们将深刻吸取教训,举一反三,进一步加强运维管理,为大家提供更优质的服务!
✅ 工业级无指责复盘
2026-10-24 任务调度中枢 503 故障分析与整改报告
一、故障概述
2026-10-24 03:10:00 至 03:18:29 UTC(共 8 分 29 秒),生产调度网关出现全线 503,交付请求失败率达 98.2%。受损请求共 419 笔,均已在服务恢复后完成幂等补偿重试,无数据丢失。二、根因剖析
- 南烛节点历史遗留的分钟级兜底 Cron 与 Cloudflare 定时任务并发打库,触发 PostgreSQL advisory 锁竞争锁死。
xact advisory锁生命周期绑定到外部事务 COMMIT,导致代码块内无法提前释放,阻塞后续所有写入连接。- 监控脚本对代理超时的判据错误,将死线超时误判为目标账号封禁,触发了自杀式循环重试与熔断。
三、止血与整改措施
- 止血:03:14:10 手动下线南烛残留 Cron,应用迁移脚本 009 拆分维护事务独立提交,连接池恢复。
- 物理防线(已上线):
- 提交
f07745d:引入调度互斥分布式租约,租约超期自动回收,杜绝单机僵尸进程竞争;- 迁移 010:重构锁粒度为行级乐观并发控制(
WHERE rev = $1),彻底弃用事务级 advisory 锁;- 监控脚本已修正返回码匹配逻辑,明确区分网络超时与业务拒绝。
四、📋 Postmortem 扣分清单(Deduction Rubric)
发布任何事故通报或故障复盘前逐条核验,命中任何一项扣 25 分(满分 100,低于 75 分重写):
| 违规维度 | 扣分项(Anti-pattern) | 扣分 | 为什么致命 | 修正方案 |
|---|---|---|---|---|
| 首屏量化 | 使用“部分用户/轻微影响/短时间”等模糊词 | -25 | 破坏专业信任感,显得刻意粉饰。 | 必须给出故障起止秒数、受影响请求准确数量/百分比、脏数据量。 |
| 虚假客套 | 出现“敬请谅解/深表歉意/不便之处”等空洞公关套话 | -25 | 纯情绪消耗,没有信息量,激化读者不满。 | 砍掉所有公关修辞,用具体的补偿方案与恢复事实说话。 |
| 归咎个人 | 归因于“员工疏忽/人为失误/经验不足” | -25 | 掩盖系统缺陷,惩罚个人并不能阻止下一个人在同一个坑翻车。 | 下钻到机制缺陷:为什么系统允许未经审计的输入被直接执行? |
| 整改无力 | 整改项写“加强培训/深刻反思/提高警惕”等自觉承诺 | -25 | 纯口头保证,事故必然会以换皮方式再次复发。 | 必须是物理约束(自动化门禁、超时断开、数据库约束、CI 拦截)。 |


