
🎯 学什么:掌握系统化的事故调查方法论——从现象到根因的六步推理框架。核心洞察:调查中最危险的不是「找不到原因」,而是「找到第一个疑似原因就觉得找到了」——这就是锚定效应。一旦锚定了第一个假设,后续所有搜索都在「证明它是对的」而非「验证它是不是真的」。六步框架强制你先列多个假设、逐一排除,而非跳结论。 💡 难易度:⭐⭐ | ⏱️ 预计时间:30 分钟
1. 课程概览
💡 白话小课堂:你家厨房水管突然漏水了。你会怎么做?A)直接拆墙找水管——可能拆错了墙。B)先观察水从哪里流出来的、什么时候开始的、水流多大,列出可能的原因(水龙头坏了?水管裂了?楼上漏水?),然后逐一排除。B 就是六步调查框架——不跳结论、不猜答案、用证据说话。
来源:Garry Tan (YC CEO) / gstack
2. 六步调查框架详解
Step 1:精确定义问题
「网站挂了」不是问题定义,是模糊描述。
精确的问题定义必须包含四个要素:
什么坏了?
✗ 「支付系统出问题了」
✓ 「/api/checkout 端点错误率从 0.1% 升至 47%」
什么时候开始的?
✗ 「刚才」
✓ 「从 14:32 开始,持续了 18 分钟」
影响了多少用户?
✗ 「很多用户」
✓ 「影响所有移动端用户(约 120 万,占总用户 23%),桌面端正常」
影响程度如何?
✗ 「挺严重的」
✓ 「成功下单率从 98.7% 降至 12%,每分钟损失约 ¥43 万」
为什么精确的问题定义这么重要?
如果问题定义是「网站挂了」:
→ 调查方向完全发散——前端?后端?网络?数据库?
→ 每个方向都是「可能」,没有优先级的依据
→ 团队分散排查,互相干扰
如果问题定义是「移动端 /api/checkout 14:32 开始错误率 47%,桌面端正常」:
→ 关键线索:仅移动端 → 排除了全局性的数据库/后端问题
→ 关键线索:14:32 开始 → 聚焦该时间点前后的变更
→ 调查方向立刻收窄 80%
Step 2:收集证据
不要问「最近改了什么」,直接查数据。
五类证据来源(按优先级排列):
1. 监控系统(最快、最客观)
→ 错误率、延迟、QPS、CPU/内存/磁盘
→ Grafana / Datadog / Prometheus 的仪表盘截图
→ 重点:找到「异常是从什么指标开始的」——第一个异常的指标就是线索的起点
2. 日志系统(细节最丰富)
→ 应用日志(错误栈、请求/响应 payload)
→ 中间件日志(数据库慢查询、Redis 超时、消息队列积压)
→ 重点:找到「最早的报错日志」——它的时间戳和错误类型是最直接的线索
3. 变更记录(不要靠记忆)
→ 部署历史(什么服务、什么版本、什么时候部署的)
→ 配置变更(功能开关、环境变量、Nginx/K8s 配置)
→ 基础设施变更(扩缩容、数据库迁移、DNS 变更)
→ 查询方式:CI/CD 的部署记录 + 配置管理系统(Consul/Apollo/Nacos)的变更日志
4. 用户反馈(最容易被忽略但最有价值)
→ 客服工单(用户描述的「症状」可能比监控更具体)
→ 社交媒体(Twitter/微博上的用户抱怨——有时比告警还快)
→ App Store 评论(iOS 崩溃问题可能用户比你更早知道)
5. 环境状态(排除法)
→ 服务器健康状态(单机故障?集群问题?)
→ 第三方服务状态(支付网关?短信服务?CDN?)
→ 网络状态(丢包率、DNS 解析、防火墙规则)
🔑 核心原则:Step 2 的唯一目标——不等任何人、不靠任何人记忆。人在压力下会漏记、选择性遗忘、甚至本能地避开「可能跟自己有关」的线索。数据不会撒谎。
Step 3:形成假设(最关键的一步)
这是整个调查中最容易被跳过、也是最危险的一步。
锚定效应在事故调查中的表现:
事故发生后:
→ 某工程师:「14:30 前端刚部署了一个版本,肯定是这个!」
→ 团队立刻围绕「前端部署」展开调查
→ 2 小时后发现跟前端完全无关 → 浪费了黄金 2 小时
正确的做法——先列假设、再排序:
→ 假设 A:前端部署引入了 JS 错误(可能性:中)
→ 假设 B:支付网关下游故障(可能性:高 —— 历史数据:上个月就出现过)
→ 假设 C:数据库连接池耗尽(可能性:中 —— 跟「仅移动端影响」矛盾)
→ 假设 D:CDN 缓存策略变更(可能性:低 —— 没有相关变更记录)
排序后按「可能性 × 影响程度」从高到低依次验证。
多假设思维的操作方法:
强制规则:在任何调查开始时,必须列出至少 3 个不同的假设。
为什么是 3 个?
→ 1 个假设 → 锚定效应高风险
→ 2 个假设 → 容易陷入「A 还是 B」的二元思维,忽略 C
→ 3+ 个假设 → 强迫你考虑「还有什么可能」,打破锚定
每个假设的格式:
假设 X:(可能性:高/中/低)[一句话描述]
支持证据:[为什么觉得是这个?]
反对证据:[哪些观察到的事实跟这个假设矛盾?]
验证方法:[怎么快速确认或排除?]
验证成本:[需要多长时间?需要谁参与?]
⚠️ 避坑指南:反对证据和验证方法是假设模板中最容易被跳过的两个字段。人的本能是只找支持证据(确认偏误),但能推翻假设的证据才是最有价值的。
Step 4:测试假设
快速排除比慢慢确认更高效。
验证策略:优先验证「验证成本最低」或「影响程度最高」的假设
验证方法从快到慢:
1. 回滚最近的变更 → 几分钟内判断是否有因果关系
2. 查询日志/监控的特定指标 → 秒级判断
3. 在测试环境复现 → 需要搭建环境,慢
4. 在生产环境做受控实验 → 最慢且风险最高,最后手段
排除法原则:
→ 每个假设验证后只有两个结果:确认成立 / 彻底排除
→ 不要有「可能成立、也可能不成立」的模糊结论
→ 如果验证结果模糊 → 说明假设定义不够精确 → 回到 Step 3 细化假设
有效验证 vs 无效验证:
有效验证:
✓ 「回滚 14:30 的前端部署后,错误率恢复 → 前端部署与事故有因果关系」
✓ 「数据库慢查询日志显示 14:32 开始 Redis 超时 → 数据库不是根因,Redis 是」
✓ 「ping 支付网关延迟正常 → 支付网关不是根因」
无效验证:
✗ 「看起来是前端的问题」—— 没有具体测试
✗ 「数据库没问题,因为以前也这样」—— 以前不代表现在
✗ 「问过支付团队了,他们说应该不是」—— 口头确认 ≠ 数据验证
Step 5:确认根因
能稳定复现 ≠ 找到了根因。根因是最深层的那个「为什么」。
5 Whys 方法(从表面现象挖到根因):
表面现象:用户在支付页面看到「系统繁忙」
Why 1:为什么支付页面报错?→ 因为 /api/checkout 返回 500
Why 2:为什么 /api/checkout 返回 500?→ 因为 Redis 缓存服务超时
Why 3:为什么 Redis 超时?→ 因为 order_recs:cache 键占用了 14GB 内存
Why 4:为什么这个键膨胀到 14GB?→ 因为推荐算法实验缓存了 35000 维特征数据(正常是 600 维)
Why 5:为什么没有提前发现?→ 因为 Redis 告警阈值设在 90%,没到 90% 但单个大 key 拖垮了访问延迟
根因:推荐算法实验的缓存维度增加了 58 倍(600 → 35000),且没有缓存容量影响评估作为上线前置条件。
注意:前 3 个 Why 是「技术原因」,后 2 个 Why 是「流程/组织原因」。好的 RCA 必须覆盖两者。
确认根因的两个标准:
标准 1:能解释所有观察到的现象
→ 如果根因是「Redis 缓存膨胀」,那必须也能解释「为什么仅移动端受影响」
→ 如果解释不了 → 说明根因不完整,还有协因
标准 2:修复根因后问题不再复发
→ 止损措施(清缓存、重启服务)让系统恢复 → 但根因没修
→ 预防措施(上线前缓存容量检查)→ 同类问题不再出现
→ 两者都需要,但只有后者解决了根因
Step 6:修复与预防
只止血不建免疫系统 = 下次还会流。只建免疫不止血 = 血流光了。
即时修复(止血):
→ 关闭推荐算法实验
→ 清理 Redis 缓存
→ 验证错误率恢复
→ 目标:「系统恢复运行」
长期预防(建免疫):
1. 缓存容量监控:新增 key 大小超 500MB 自动告警
2. 上线检查清单:算法模型上线前必须评估缓存/内存/CPU 影响
3. 灰度规则强化:推荐算法实验默认 1% 流量运行 24 小时后再扩量
4. 告警阈值调整:Redis 使用率告警从 90% 下调到 70%
5. 容量规划评审制度:任何资源使用增长超过 3 倍的变更需要架构评审
预防措施的三个检验标准:
→ 是否具体可执行?(不是「要加强监控」而是「新增 key 超 500MB 告警」)
→ 是否能量化?(不是「及时告警」而是「70% 阈值、5 分钟连续超阈值」)
→ 是否系统化?(不是「团队以后注意」而是「合并到 CI/CD 检查清单中」)
3. 电商案例:订单支付成功但库存未扣减的根因排查
🛒 实战案例:某电商平台(日均订单180万单),2025年双11大促后第3天(11月14日),商家群开始集中投诉——"用户付款成功了,但我们后台库存没有扣减""已经付了款的订单状态还停留在待支付"。投诉在2小时内从零星8条暴涨至347条。
事故时间线与六步调查:
11/14 14:00 首条投诉:1个商家反馈"订单付了但库存没减"
11/14 14:30 投诉增至47条——客服升级为P1事故
11/14 14:35 Step 1(精确定义问题):
精确描述——"11/14 13:00起,约30%的支付成功订单未触发库存扣减回调,
影响全平台所有品类商家(非特定品类),
已确认支付成功但库存未扣的订单约12,000单(持续增长中)。
致命风险:库存未扣减→商品仍可被购买→超卖风险。
预计每分钟新增约80单受影响的订单。"
11/14 14:42 Step 2(收集证据):
监控系统:支付服务 payment-service 的 P99 延迟从80ms升至420ms
日志系统:最早的异常日志 "stock_deduct_timeout" 出现在13:02:17
变更记录:无部署记录(上次部署是11/11)
但!11/13 23:50 有一条配置变更记录:
"payment-service 的 stock_deduct 回调超时从 300ms 调整为 200ms"
理由:"优化支付链路,减少用户等待时间"
用户反馈:商家群投诉 + 平台客服工单
环境状态:数据库连接池正常,Redis正常,消息队列积压中(Kafka lag 从200增至48,000)
11/14 14:48 Step 3(形成假设——强制至少3个):
假设A:11/13 23:50的配置变更(超时300ms→200ms)导致库存扣减回调在200ms后超时
→ 但库存服务实际响应时间P95为280ms(不受配置变更影响)
支持证据:最早的"stock_deduct_timeout"出现在配置变更后约13小时(13:02)
— 因为该时段是流量低谷,之前12小时内单量少没有触发超时
反对证据:无——时间线和日志完美吻合
验证方法:将超时配置回滚到300ms,观察日志中timeout是否消失
验证成本:5分钟,运维一人操作
假设B:库存服务 stock-service 本身出现性能衰退
支持证据:无——库存服务P99延迟稳定在250ms,无异常
反对证据:库存服务延迟正常,响应成功率99.8%
验证方法:检查库存服务近24小时性能趋势
验证成本:2分钟,查询监控
假设C:数据库或网络问题导致调用失败
支持证据:无——其他服务调用库存扣减正常
反对证据:同一时段其他服务的回调正常
验证成本:5分钟
11/14 14:53 Step 4(测试假设——先验证成本最低+可能性最高的):
先验证假设C(最快):查询库存服务监控→正常 → 假设C排除
再验证假设A(可能性最高+成本低):将超时配置从200ms回滚到300ms
→ 4分钟后,"stock_deduct_timeout"日志停止出现
→ 消息队列积压开始消退
→ 假设A被确认
11/14 15:10 Step 5(确认根因——5 Whys):
现象:支付成功但库存未扣减
Why 1: 为什么库存未扣减?→ payment-service调用stock-service扣减库存超时
Why 2: 为什么超时?→ 超时阈值从300ms被改为200ms
(但库存服务实际P95响应时间=280ms,超过了200ms的新阈值)
Why 3: 为什么有人在双11后3天做配置变更?→ 运营优化需求"减少支付等待时间",
运维在11/13晚执行了配置热更新
Why 4: 为什么配置变更没有经过充分测试?→ 该超时配置项被标记为"低风险",
允许运维直接修改,无需代码审查或灰度验证
Why 5: 为什么没有在双11冻结期内拦截?→ 代码冻结策略在11/11 23:59解除,
但未定义"解冻后48小时内仅允许紧急变更"的缓冲规则。
根因不是"有人改错了配置",而是"没有机制来识别'恢复期'和'正常期'的区别"。
11/14 15:15 Step 6(修复与预防):
即时修复(止血):
→ 回滚超时配置(200ms→300ms)✅
→ 重放积压的Kafka消息(约48,000条库存扣减事件)——预估2小时内消化
→ 通知受影响商家:库存已恢复正常,超卖订单自动取消并退款
长期预防(建免疫):
1. 配置项风险分级:所有影响支付链路的配置项标记为"高风险"——
需代码审查+测试环境验证+灰度发布(至少1%流量验证60分钟)
2. 双11解冻缓冲规则:冻结解除后72小时内,仅允许P0事故修复——
其余配置变更一律进入审核队列
3. 超时配置合理性校验:系统自动对比"配置超时值"与"目标服务实际P95响应时间"——
如果超时<实际P95,CI自动拒绝并告警
(事故中:配置200ms < 实际P95 280ms → 应该是不可保存的配置)
4. Kafka lag 告警阈值:库存扣减事件 lag > 500 → P1告警
(事故中lag从200涨到48,000才被发现——没有告警)
5. 配置变更"冷静期":涉及支付链路的高风险配置变更——
保存后延迟5分钟生效(不是即时生效),给观察窗口
受影响范围与损失:
- 受影响订单:约12,000单(支付成功但库存未扣)
- 超卖订单:1,847单(库存未扣→其他用户仍可购买→超卖→需退款)
- 直接退款金额:约¥53万
- 商家投诉工单:347条
- 事故持续时间:13:02→15:15(约2小时13分,含调查和修复)
- 如果六步框架中的"先列3个假设+优先验证成本最低的"没有被执行,团队可能会花2-3小时排查数据库/网络——事故持续时间可能延长到5-6小时
关键转折分析: 调查中最关键的时刻不是"找到根因",而是14:48的Step 3——在所有人都倾向于"一定是库存服务出问题了"的时候,调查负责人强制要求先列至少3个假设。假设A(配置变更)被列入后,反对证据为零(时间线和日志完美吻合),验证成本又最低(5分钟回滚配置)——所以被优先验证。如果直接锚定在"库存服务性能"上(看似最合理的猜测),排查方向会完全跑偏,事故持续时间至少多3小时。
🔑 启示:事故调查中最危险的不是"找不到原因",而是"找到第一个疑似原因就觉得找到了"。本次调查能在2小时内定位根因,不是因为团队更聪明,而是因为强制执行了"至少3个假设+优先验证成本最低的"。配置回滚只用了5分钟——如果这5分钟的验证被推迟到"排查完库存服务数据库和网络"的3小时之后才做,事故影响将扩大数倍。
4. 结构拆解:问题调查型 Skill 模板
问题调查型 Skill 模板
核心特征
→ 管理对象 = 事故/故障的调查过程 → 核心原则 = 多假设 + 逐一验证 + 5 Whys → 关键设计 = 六步调查框架 + 证据来源分类 + 锚定效应防御
通用结构
Investigation Framework(六步调查框架)
Step 1: Define(精确定义问题) 四要素:什么坏了 + 什么时候开始 + 影响多少用户 + 影响程度 用数据替代模糊描述
Step 2: Evidence(收集证据) 五类来源(按优先级):
- 监控系统 → 日志系统 → 变更记录 → 用户反馈 → 环境状态 原则:查数据不靠记忆
Step 3: Hypotheses(形成假设) ← 最容易被跳过 强制规则:至少 3 个假设 每个假设含:可能性评级 / 支持证据 / 反对证据 / 验证方法 / 验证成本
Step 4: Test(测试假设) 优先证伪成本最低的假设 回滚 → 日志查证 → 测试复现 → 生产实验
Step 5: Confirm(确认根因) 5 Whys → 覆盖技术原因 + 流程/组织原因 两个标准:能解释所有现象 + 修复后不复发
Step 6: Prevent(修复与预防) 即时修复(止血)+ 长期预防(建免疫) 预防措施:具体 + 量化 + 系统化
5. 掌握检验
Q1:六步调查框架中,哪一步最容易被人跳过?「锚定效应」为什么在事故调查中特别危险?
Q2:Step 1(精确定义问题)中,「网站挂了」这个描述有什么问题?请将「网站挂了」改写为精确的问题定义。
Q3:在 Step 2(收集证据)中,为什么「直接查看部署历史和配置变更记录」比「问『最近改了什么』」更可靠?
- A) 人能记住所有改动,问一下更快
- B) 人在压力下会回答「什么都没改」,数据不会撒谎
- C) 部署历史通常不准确
- D) 问比查更快,调研应该讲究效率
Q4:课程案例中,从 14:32 告警到确认根因(推荐算法缓存膨胀 60 倍),团队经历了什么关键转折?为什么最初被标记为「头号嫌疑犯」的前端部署最终被排除了?
Q5:Step 6(修复与预防)中,「长期预防措施」和「即时修复」的区别是什么?为什么两者缺一不可?课程案例中提出了 5 条长期预防措施,请列出至少 3 条。
Q6:以下哪项不是 Step 2(收集证据)中应该检查的五类来源之一?
- A) 监控系统
- B) 竞品的行为
- C) 变更记录
- D) 用户反馈
Q7:请用六步调查框架分析一个你熟悉的技术问题(可以是真实的,也可以是模拟的),完成 Step 1 到 Step 6 的完整推理过程。特别要求:在 Step 3 中列出至少 3 个不同的假设。
6. 答案
点击查看答案
Q1:参考答案 — Step 3(形成假设 → 列出多个可能性并排序)最容易被人跳过。人的本能是看到第一个疑似原因就认定这就是根因——这叫「锚定效应」。一旦锚定了第一个假设,后续所有搜索证据都在「证明它是对的」(确认偏误),而不是「验证它是不是真的」。课程案例:如果团队锚定了「14:50 的前端部署」而不进一步形成多个假设,就会浪费大量时间排查错误方向。
Q2:参考答案 — 「网站挂了」是模糊描述,无法指导调查。精确版本:「从 14:32 开始,/api/checkout 端点的错误率从 0.1% 升至 47%,影响所有移动端用户(桌面端正常),受影响用户约 120 万(占总用户的 23%)。」精确的问题定义包含:什么坏了、什么时候开始的、影响范围和程度——用具体数据替代模糊描述。
Q3:B — 人在压力下会漏记或选择性遗忘(尤其是怕「背锅」的时候)。数据不会撒谎:直接查看部署历史、配置变更记录和基础设施变更日志,才能得到客观的时间线和因果线索。
Q4:参考答案 — 关键转折:回滚了 14:50 的前端部署后问题未解决 → 这说明假设 A(头号嫌疑犯)被排除。团队没有锚定在假设 A 上,而是立即转向假设 B(Redis 异常),发现了 order_recs:cache:* key 从 200MB 膨胀至 14GB。最终锁定根因:推荐算法团队在 15:01 开启的实验将缓存数据模型从 600 维扩展到 35000 维,缓存占用膨胀 60 倍。如果不是严格的「多假设 → 逐一验证」流程,团队可能会在前端部署上浪费很久。
Q5:参考答案 — 即时修复(如关闭实验、清理缓存)是「止血」——让系统恢复运行。长期预防措施是「建免疫系统」——确保同样的问题不会再发生。两者缺一不可:光止血不建免疫 = 下次还会流;光建免疫不止血 = 血流光了免疫也没用了。课程案例 5 条措施:(1) 缓存 key 大小监控告警;(2) 算法上线检查清单新增「缓存容量影响评估」;(3) 推荐算法实验默认 1% 流量运行 24 小时后再扩量;(4) Redis 告警阈值从 90% 调整到 70%;(5) 容量规划评审制度。
Q6:B — 「竞品的行为」不是五类证据来源之一。五类来源是:监控系统、日志系统、变更记录、用户反馈(客服工单/社交媒体)、环境状态(服务器健康/第三方服务状态)。
Q7:参考答案(示例)—
- Step 1(定义问题):从 16:00 开始,用户登录成功率从 99.7% 降至 72%,影响全部用户,持续了 25 分钟。
- Step 2(收集证据):监控显示 Redis 认证服务的 CPU 100%;部署记录 15:55 有「Redis 配置热更新」;日志显示 auth service 每秒报 3000 次 timeout;无用户大规模投诉(因为自动重试机制掩盖了部分失败)。
- Step 3(形成假设):假设 A(85%)——15:55 的 Redis 配置更新引入了错误的连接池大小设置;假设 B(10%)——Redis 集群中某个节点硬件故障导致级联失败;假设 C(5%)——大规模的外部暴力破解攻击导致认证服务过载。
- Step 4(测试):回滚 Redis 配置 → 问题立即恢复 → 确认假设 A;检查 Redis 硬件监控 → 无异常(排除 B);检查 auth 日志 → 无异常登录请求频率(排除 C)。
- Step 5(确认根因):连接池从默认 50 个连接被错误配置为 5 个,在高并发下所有连接被占满,新请求排队超时。
- Step 6(修复与预防):立即修复 → 回滚配置。长期预防:(1) Redis 配置变更必须走代码审查而非直接热更新;(2) 连接池配置添加最小值校验(< 10 自动拒绝);(3) 认证服务添加连接池使用率告警(> 70% 预警)。
(5/7 通过)
7. 延伸阅读
- [[L4-17-谨慎模式|上一课:谨慎模式]] —— 危险操作自动减速
- [[L4-19-学习模式|下一课:经验学习]] —— 不让团队在同一个坑里跌倒两次

评论区
共 0 条评论