版本:v3.0
适用范围:生产环境故障、重大线上问题、服务中断事件
目标读者:技术团队负责人、SRE、开发工程师、项目经理
核心原则:找到真正的故障根源,修正现行做法,防止同类问题再次发生
在事故发生后,深入分析产生事故的原因,并撰写完整的复盘报告,主要目标是了解当前系统、流程中的缺陷,完善系统和流程,避免同类问题的再次发生。
复盘报告的好坏,最重要的判断标准是:是否找到了真正的引发问题的原因和事故发生环境中的缺陷。本规范的目的,就在于引导发现最直接、最到位的故障根源。
在没有规范约束的情况下,事故复盘往往会出现以下问题:
本规范通过六大归因原则和标准化复盘模板,确保每次事故都能产出可执行、可验证的改进项。
| 目标层级 | 具体描述 | 衡量标准 |
|---|---|---|
| 找到根因 | 定位最直接、最具体的故障触发点 | 能用一句话清晰描述"发生了什么导致什么" |
| 发现缺陷 | 识别系统、流程、监控中的薄弱环节 | 至少发现 1 个系统性缺陷 |
| 产出改进 | 生成可执行、可跟进的改进项 | 每个改进项有负责人和截止日期 |
| 知识沉淀 | 将事故经验转化为团队共享知识 | 复盘报告可被第三方独立理解 |
| 文化塑造 | 建立"对事不对人"的改进文化 | 同一类事故不重复发生 |
在对事故进行 Root Cause Analysis 的过程中,需要遵循以下六大原则。这些原则相互关联,共同确保归因的准确性、可操作性和建设性。
原则:每个事故原则上必须有且只有一个主要归因(Primary Root Cause)。但在复合故障等特殊场景下,允许经过评审后认定多个主要归因。
事故往往由多个因素共同导致,但如果不区分主次,复盘会陷入"每个因素都是原因"的泥潭,最终导致:
主要归因应当满足以下条件:
其他相关因素应归类为:
示例(单一故障):
- 主要归因:订单服务在数据库连接池耗尽时未触发熔断,导致级联故障
- 促成因素:促销活动期间流量激增 5 倍
- 缺失防护:缺少连接池监控告警
- 发现延迟:业务方投诉 15 分钟后才定位到技术问题
现代分布式系统的故障往往是多系统耦合失效的结果。例如:
三个系统各有一个缺陷,单独存在都不会出事,但组合在一起才导致故障。此时"只有一个主要归因"可能:
复合故障判定标准:
当满足以下条件时,可认定为复合故障,允许多个主要归因:
复合故障的处理流程:
示例(复合故障):
- 主要归因 1(订单服务团队):订单查询接口在高并发下未启用缓存,导致数据库压力激增
- 主要归因 2(支付服务团队):支付回调熔断策略配置错误,异常情况下未触发熔断
- 主要归因 3(运维团队):降级开关配置错误,本应关闭非核心功能但未生效
- 改进项:每个主要归因对应独立的 P0 改进项,由各自团队负责
原则:所归因的根本原因,应当指向某个系统自身的行为(如发版、配置变更等),而不止于外部因素。
| 外因(外部触发) | 内因(系统缺陷) |
|---|---|
| 磁盘满 | 日志轮转策略未生效 / 监控未告警 |
| 请求量增大 | 系统在高并发环境下的瓶颈点未识别 |
| 上游服务超时 | 下游未设置合理的超时和降级策略 |
| 第三方 API 变更 | 缺少接口契约测试或版本兼容性检查 |
| 网络抖动 | 重试策略过于激进,导致雪崩 |
将外因转换为内因的思维方式:
外因:磁盘满了导致服务崩溃
↓ 转换
内因:日志清理策略配置错误,导致磁盘空间耗尽时未触发自动清理
外因:上游推送了不兼容的字段格式
↓ 转换
内因:缺少输入数据的 Schema 校验和兼容性测试
外因:数据库主从延迟导致读取旧数据
↓ 转换
内因:读操作未根据业务场景选择合适的一致性级别
关键认知:外部因素永远存在,无法消除。真正可控的是系统对外部因素的响应方式。
原则:寻找是因为"做了什么"而导致的问题,而不要对"没有做什么"进行过度的展开。
| 类型 | 示例 | 评价 |
|---|---|---|
| ❌ 没有做什么 | "监控不足,导致没能自己发现问题" | 不应作为主要归因 |
| ✅ 做了什么 | "新上线的批处理任务在异常情况下未限制并发数,导致数据库连接池耗尽" | 可作为主要归因 |
| ❌ 没有做什么 | "缺少压力测试,不知道系统瓶颈" | 不应作为主要归因 |
| ✅ 做了什么 | "发布的配置变更未经过灰度验证,直接全量生效导致兼容性故障" | 可作为主要归因 |
每个项目都有大量"没有做到位"的事情:
如果针对"没有做什么"展开分析,常常能列出十几条"需要做但一直没做"的事项。这种讨论:
将"没有做什么"转换为"做了什么":
❌ "缺少自动化测试"
↓ 转换
✅ "本次重构修改了核心支付流程,但仅通过人工验证,未执行自动化回归测试"
❌ "监控不完善"
↓ 转换
✅ "新上线的缓存层未接入统一监控平台,导致缓存击穿后无告警"
核心区别:"做了什么"的归因可以立即修正具体行为;"没有做什么"的归因往往变成无限期的"待办事项"。
原则:当出现上游变更导致下游故障时,因下游防卫不足的原因,总是把 100% 的责任归因到下游(即实际发生问题的那一方)。
如果没有这条原则,团队会自然形成以下推理:
上游变更 → 下游故障 → 上游背锅 → 上游减少变更 → 系统僵化
长期结果是:
下游系统应当具备的防卫能力:
| 防卫类型 | 具体措施 | 适用场景 |
|---|---|---|
| 输入校验 | Schema 验证、参数范围检查、空值处理 | 接收外部数据的所有接口 |
| 容错设计 | 超时控制、降级策略、熔断机制 | 依赖外部服务的场景 |
| 兼容性处理 | 向前兼容、字段忽略、默认值填充 | 解析外部协议/格式 |
| 监控告警 | 异常检测、业务指标监控 | 所有生产服务 |
| 灰度验证 | 金丝雀发布、A/B 测试、影子流量 | 任何变更上线 |
虽然事故归因 100% 归下游,但上游仍有义务:
注意:上游的义务属于"协作规范"范畴,不纳入事故归因。如果上游未履行义务,应在复盘报告中记录为 Contributing Factor,但不改变归因方向。
原则:当上游变更明显违反已发布的兼容性承诺或协作规范时,可作为 Contributing Factor 的升级处理。
判定标准(需同时满足):
处理流程:
示例:
场景:上游支付网关未通知就删除了回调报文中的 "transaction_id" 字段, 下游订单系统已有 Schema 校验,但该校验允许字段缺失(向前兼容设计), 导致订单无法关联支付记录 判定:上游违反了"字段删除需提前 30 天通知"的 API 兼容性承诺 处理: - 主要归因:下游订单系统的关联逻辑未处理"transaction_id 缺失"的异常分支 - 严重 Contributing Factor:上游未按承诺提前通知字段删除 - 上游改进项:[P1] 建立 API 变更审批流程,字段删除必须经过兼容性评审
场景:上游支付网关修改了回调报文格式,下游订单系统解析失败,导致订单状态未更新
❌ 错误归因:上游未提前通知就变更了格式
✅ 正确归因:下游订单系统未对回调报文进行 Schema 校验,缺少异常处理分支
改进项:
1. [P0] 订单系统增加回调报文 Schema 校验,非法格式进入人工审核队列
2. [P1] 建立上游变更通知机制(非事故归因,但需改进)
3. [P1] 回调处理增加异常告警,解析失败立即通知
原则:出现生产环境故障因素,按其性质可分为三类。在故障复盘中,应当尽量把重点集中在系统功能缺失和功能异常。
| 类别 | 定义 | 示例 | 复盘重点 |
|---|---|---|---|
| 系统功能缺失/异常 | 代码、配置、架构层面的缺陷 | 空指针异常、死锁、资源泄漏 | ⭐⭐⭐ 核心关注点 |
| 工作流程不规范 | 流程、规范执行不到位 | 未经过测试直接上线、变更未审批 | ⭐⭐ 次要关注点 |
| 人员素质不到位 | 个人能力、态度问题 | 低级错误反复出现、责任心缺失 | ⭐ 尽量避免,但不回避 |
如果确实涉及人员因素(如重复犯同类错误),应当:
重复人为失误的特殊处理:
当同一人在短期内(如 3 个月内)重复犯同类低级错误时,完全回避人员因素可能:
处理流程:
示例转换:
❌ "某开发人员在配置中填错了参数" ✅ "配置管理缺少参数校验机制,允许非法值进入生产环境" ❌ "测试人员漏测了边界场景" ✅ "测试用例生成依赖人工枚举,缺少边界值自动覆盖"
原则:归因的粒度应该适中,以实际运营操作的粒度展开分析。
| 过粗(❌) | 适中(✅) | 过细(❌) |
|---|---|---|
| 系统故障 | 订单查询接口在高并发下未启用缓存 | 消息中使用了希伯来语,其中 i 和 1 的本地化处理所使用的第三方库不支持,导致序列化失败 |
| 人为因素 | 金额输入错误 | 输入金额的时候打了个喷嚏多打了个 0 |
| 网络问题 | 跨可用区网络延迟导致分布式事务超时 | 路由器端口 3 的 BGP 会话在 14:23:05 秒闪断 |
| 数据库问题 | 慢查询未优化导致连接池耗尽 | 索引 idx_order_2023 的 B+ 树第三层节点分裂 |
一个好的归因描述应当满足:
[系统/模块] 在 [条件/场景] 下,[做了什么/没做什么],导致 [结果]
示例:
✅ "支付回调处理器在接收非 JSON 格式报文时,未进行格式校验,直接解析导致空指针异常"
✅ "定时对账任务在跨月执行时,未处理月份边界,导致日期计算错误"
✅ "缓存预热脚本在启动时未检查依赖服务可用性,导致启动失败"
补充信息的使用:过细的粒度(如具体的异常堆栈、时间戳、参数值)应放在"补充信息"或"技术细节"章节,不影响主要归因的清晰度。
撰写复盘报告的目的,在于记录整个事件,让第三方能够通过阅读复盘报告了解整个事故产生的来龙去脉及前因后果。同时也能审核所分析发现的原因,是否到位与合理,以便为后续的改进提供信息支持。
# 事故复盘报告:[事故标题]
## 1. 基本信息
- 事故编号:INC-YYYYMMNNN
- 发生时间:YYYY-MM-DD HH:MM:SS (时区)
- 发现时间:YYYY-MM-DD HH:MM:SS
- 恢复时间:YYYY-MM-DD HH:MM:SS
- 持续时间:XX 分钟
- 影响范围:[服务/功能/用户群体]
- 严重等级:P0/P1/P2/P3
- **是否为复合故障**:是/否(如为是,列出各主要归因)
## 2. 时间线(Timeline)
[精确到分钟的事件序列]
## 3. 影响评估
- 业务影响:[具体描述]
- 用户影响:[数量、范围]
- 数据影响:[是否有数据丢失/错误]
- 财务影响:[如有]
## 4. 根因分析
### 4.1 主要归因
[一句话描述]
### 4.2 促成因素
- [因素1]
- [因素2]
### 4.3 缺失防护
- [防护1]
- [防护2]
### 4.4 上游严重违规(如适用)
[描述上游违规行为及判定依据]
## 5. 改进项
| 优先级 | 改进内容 | 负责人 | 截止日期 | 状态 |
|--------|---------|--------|---------|------|
| P0 | [具体描述] | [姓名] | YYYY-MM-DD | 待开始 |
## 6. 经验总结
[团队层面的经验沉淀]
## 7. 附件
- [日志链接]
- [监控截图链接]
- [相关工单链接]
在复盘报告中出现的所有可溯源的信息,应当尽可能引用原始信息的链接或获取方式的描述,而非单纯的截图。
| 信息类型 | 引用方式 | 示例 |
|---|---|---|
| 异常信息 | 日志平台链接 + 查询条件 | [Kibana 日志](https://kibana/...?query=error_id:12345) |
| 关键时间节点 | 监控平台链接 + 时间范围 | [Grafana 监控](https://grafana/...?from=...&to=...) |
| 变更记录 | 发布系统链接 | [发布记录](https://deploy/.../release/678) |
| 告警记录 | 告警系统链接 | [PagerDuty 事件](https://pagerduty/.../incident/abc) |
| 沟通记录 | 工单/IM 链接 | [飞书工单](https://lark/.../ticket/789) |
例外情况:如果原始系统已不可用(如临时环境已销毁),则截图作为补充证据保留。
| 时间 | 事件 | 操作人 | 证据链接 |
|------|------|--------|---------|
| 14:23 | 监控告警:订单成功率下降至 85% | 系统自动 | [告警详情](...) |
| 14:25 | 值班工程师开始排查 | 张三 | - |
| 14:30 | 确认问题根因:缓存击穿 | 张三 | [排查笔记](...) |
| 14:35 | 执行降级:关闭非核心功能 | 张三 | [变更记录](...) |
| 14:40 | 订单成功率恢复至 99% | 系统自动 | [监控截图](...) |
| 事故等级 | 时间精度要求 | 事件覆盖范围 |
|---|---|---|
| P0(核心业务中断) | 分钟级 | 从告警到恢复的全流程 |
| P1(主要功能受损) | 5 分钟级 | 关键决策点和操作 |
| P2(次要功能异常) | 15 分钟级 | 主要事件节点 |
| P3(轻微影响) | 小时级 | 关键里程碑 |
原则:故障期间以恢复服务为最高优先级,时间线可以事后基于日志、监控、聊天记录补全。
操作指引:
关键认知:精确的时间线对于复盘很重要,但不应以延长恢复时间为代价。恢复服务后补全的时间线同样有效。
| 优先级 | 定义 | 完成时限 | 跟踪方式 |
|---|---|---|---|
| P0 | 防止同类事故再次发生的核心措施 | 3 个工作日内 | 每日站会跟踪 |
| P1 | 降低事故影响范围或加速发现的措施 | 2 周内 | 周会跟踪 |
| P2 | 长期系统性优化 | 1 个月内 | 迭代计划跟踪 |
每个改进项应当满足:
❌ "加强监控"
✅ "在订单支付成功率指标上增加告警:当成功率 < 95% 持续 2 分钟时,
通过 PagerDuty 通知值班工程师,告警级别 P1"
❌ "优化代码"
✅ "在订单查询接口增加 Redis 缓存,缓存有效期 5 分钟,
缓存 Key 格式:order:query:{user_id}:{date_range}"
❌ "增加测试"
✅ "在 CI 流程中增加压力测试步骤:模拟 1000 QPS 持续 5 分钟,
要求 95th 延迟 < 200ms,错误率 < 0.1%"
原则:复盘会议是技术分析会议,不是问责会议。高层领导的参与会增加心理压力,导致避重就轻。
| 阶段 | 时长 | 内容 | 规则 |
|---|---|---|---|
| 1. 事实陈述 | 10 分钟 | 按时间线陈述事故经过 | 只讲事实,不分析原因 |
| 2. 根因分析 | 20 分钟 | 用 5 Whys 或鱼骨图分析 | 遵循六大归因原则 |
| 3. 改进讨论 | 15 分钟 | 讨论改进项和优先级 | 每个改进项必须指定负责人和截止日期 |
| 4. 总结 | 5 分钟 | 总结关键发现和行动项 | 确认报告完成时间 |
5 Whys 是一种通过连续追问"为什么"来挖掘根本原因的方法。
问题:订单服务中断 30 分钟
Why 1: 为什么订单服务中断?
→ 数据库连接池耗尽,新请求无法获取连接
Why 2: 为什么连接池耗尽?
→ 定时对账任务占用了大量连接且未释放
Why 3: 为什么对账任务占用大量连接?
→ 对账任务按用户维度串行执行,每个用户开一个连接
Why 4: 为什么按用户维度串行执行?
→ 原始设计未考虑数据量增长,未做分页处理
Why 5: 为什么设计时未考虑数据量增长?
→ 缺少容量规划和性能测试环节
根因:定时任务设计缺少容量评估和性能测试,
未对大数据量场景做分页和连接复用优化
鱼骨图用于系统性梳理可能导致问题的各类因素。
| 类别 | 内容 | 技术系统对应 |
|---|---|---|
| Man(人员) | 操作失误、技能不足 | 值班响应、变更执行 |
| Machine(机器) | 硬件故障、资源不足 | 服务器、网络、存储 |
| Method(方法) | 流程缺陷、规范缺失 | 发布流程、测试方法 |
| Material(材料) | 数据问题、配置错误 | 代码、配置、数据 |
| Measurement(测量) | 监控缺失、指标不准 | 告警、日志、监控 |
| Mother Nature(环境) | 外部依赖故障 | 第三方服务、网络环境 |
当事故与变更相关时,使用以下框架分析:
| 变更类型 | 风险等级 | 常见事故模式 |
|---|---|---|
| 代码发布 | 高 | 逻辑错误、性能退化、兼容性问题 |
| 配置变更 | 高 | 参数错误、格式不兼容、范围越界 |
| 数据库变更 | 极高 | 锁表、慢查询、数据不一致 |
| 基础设施变更 | 中 | 网络连通性、资源分配、权限问题 |
| 依赖升级 | 中 | API 不兼容、行为变更、性能退化 |
□ 变更内容:具体改了什么?
□ 变更范围:影响哪些系统/模块?
□ 变更时间:与事故时间是否吻合?
□ 回滚验证:回滚后问题是否消失?
□ 灰度情况:是否经过灰度?灰度期间有无异常?
□ 测试覆盖:变更是否经过测试?测试场景是否覆盖事故场景?
□ 审批流程:变更是否经过审批?审批人是否了解风险?
提出 → 评审 → 排期 → 实施 → 验证 → 关闭
| 阶段 | 负责人 | 交付物 | 时限 |
|---|---|---|---|
| 提出 | 复盘会议 | 改进项清单 | 复盘当天 |
| 评审 | 技术负责人 | 优先级和可行性确认 | 复盘后 1 天 |
| 排期 | 项目经理 | 迭代计划/工单 | 复盘后 2 天 |
| 实施 | 指定工程师 | 代码/配置/文档 | 按优先级时限 |
| 验证 | QA/SRE | 验证报告 | 实施后 1 周 |
| 关闭 | 技术负责人 | 改进项关闭确认 | 验证通过后 |
| 改进类型 | 验证方法 | 通过标准 |
|---|---|---|
| 代码修复 | 代码 Review + 回归测试 | 测试用例全部通过 |
| 监控告警 | 故障演练 / 模拟触发 | 告警在 2 分钟内送达 |
| 流程优化 | 流程审计 / 检查清单 | 下次变更 100% 遵循新流程 |
| 容量优化 | 压力测试 | 目标 QPS 下延迟和错误率达标 |
| 文档更新 | 文档 Review | 新成员能按文档独立完成操作 |
建立以下指标衡量复盘改进的有效性:
| 指标 | 定义 | 目标值 |
|---|---|---|
| MTTD (Mean Time To Detect) | 从故障发生到被发现的时间 | < 5 分钟 |
| MTTR (Mean Time To Recover) | 从发现到恢复的时间 | < 30 分钟 (P0) |
| 复发率 | 同类事故重复发生的比例 | < 5% |
| 改进完成率 | 复盘提出的改进项按时完成的比例 | > 90% |
| P0 改进超时率 | P0 改进项未在 3 天内完成的比例 | < 10% |
| 鼓励 | 避免 |
|---|---|
| 主动上报事故,不隐瞒 | 掩盖问题、延迟上报 |
| 分享事故经验,帮助他人 | 把事故当作"黑历史"避而不谈 |
| 聚焦系统改进,而非追责 | 在复盘会上批评个人 |
| 承认不确定性,"我不知道" | 假装知道、随意猜测 |
| 感谢发现问题的人 | 抱怨"谁又把环境搞坏了" |
| 等级 | 定义 | 示例 | 响应要求 |
|---|---|---|---|
| P0 | 核心业务中断,大量用户受影响 | 支付失败、登录不可用 | 立即响应,15 分钟内恢复 |
| P1 | 主要功能受损,部分用户受影响 | 订单查询慢、部分功能异常 | 30 分钟内响应,2 小时内恢复 |
| P2 | 次要功能异常,少量用户受影响 | 统计报表延迟、非核心功能不可用 | 2 小时内响应,当天恢复 |
| P3 | 轻微影响,无用户感知 | 日志异常、监控误报 | 工作时间内响应 |
在以下场景,需要 SRE 或技术负责人作为"归因裁判",确保原则不被机械执行:
| 场景 | 裁判职责 | 决策方式 |
|---|---|---|
| 复合故障判定 | 判断是否满足复合故障标准 | 复盘会议投票(2/3 以上同意) |
| 上游严重违规 | 判定上游是否违反兼容性承诺 | 技术委员会评审(2/3 以上同意) |
| 重复人为失误 | 决定是否启动针对性培训/调岗 | 技术负责人与 HR 协商 |
| 归因争议 | 当团队对主要归因有分歧时裁决 | 基于六大原则和数据证据判定 |
| 用途 | 工具 | 说明 |
|---|---|---|
| 日志查询 | ELK / Loki / Splunk | 集中化日志搜索和分析 |
| 监控告警 | Prometheus + Grafana / Datadog | 指标采集和可视化 |
| 链路追踪 | Jaeger / Zipkin / SkyWalking | 分布式请求追踪 |
| 事件管理 | PagerDuty / OpsGenie | 告警分级和值班管理 |
| 文档协作 | Notion / Confluence / Wiki.js | 复盘报告和知识库 |
| 变更管理 | Spinnaker / ArgoCD / 自研平台 | 发布审批和追踪 |
最后更新:2026-04-29
维护者:基础技术部
反馈渠道:如有疑问或建议,请在技术部群聊中提出,或提交 Wiki 评论