8.3 线上排错与复盘方法论


文档摘要

8.3 线上排错与复盘方法论 本节摘要:故障处理分两幕:现场(止血优先、证据保护、假设验证)与事后(把根因写成制度)。本节给出从告警到根因的排错决策树、JVM 三板斧的取证清单、"五问法"根因分析,和一份可直接落地的事后复盘模板——让每个事故都变成系统的免疫力,而不是重复的学费。 第一幕:黄金十分钟的动作序列 支付服务 P99 告警触发。错误的时间线是:一群人挤进会议室七嘴八舌、有人开始翻代码猜原因、有人手忙脚乱重启把现场毁了。正确的时间线是三条并行的动作流: 止血流(第一优先级,与诊断并行):"最近十分钟内变更过什么?"——发布、配置、开关、流量,八成的故障与变更相关(第 7.2 节的 SMS SDK、第 5.2 节的新版本死锁都是变更引入)。有变更先回滚,回滚不需要理解根因;

8.3 线上排错与复盘方法论

本节摘要:故障处理分两幕:现场(止血优先、证据保护、假设验证)与事后(把根因写成制度)。本节给出从告警到根因的排错决策树、JVM 三板斧的取证清单、"五问法"根因分析,和一份可直接落地的事后复盘模板——让每个事故都变成系统的免疫力,而不是重复的学费。

第一幕:黄金十分钟的动作序列

支付服务 P99 告警触发。错误的时间线是:一群人挤进会议室七嘴八舌、有人开始翻代码猜原因、有人手忙脚乱重启把现场毁了。正确的时间线是三条并行的动作流:

止血流(第一优先级,与诊断并行):"最近十分钟内变更过什么?"——发布、配置、开关、流量,八成的故障与变更相关(第 7.2 节的 SMS SDK、第 5.2 节的新版本死锁都是变更引入)。有变更先回滚,回滚不需要理解根因;没有变更则降级(摘流量、关非核心功能、限流)。止血的目标是把影响面积按住,不是把问题查清——排查是第二幕的事。

取证流(重启/回滚前必做):证据是易腐品。三件套各花一分钟:

jstack <pid> > jstack-$(date +%H%M).txt # 线程状态 死锁 阻塞点 jmap -dump:live,format=b,file=heap.hprof <pid> # 堆现场 第6.1节的案发照片 jstat -gcutil <pid> 1000 > gc-snap.txt # GC 快照

加上:最近一段 GC 日志的归档、数据库慢日志与进程监控截图、告警时间轴导出。重启销毁的是堆与线程现场——没有 dump 的 OOM 复盘只能靠猜(第 6.1 节的教训,生产预配 HeapDumpOnOutOfMemoryError 就是为了这一刻)。

观测流:拉出时间轴对齐看——告警时刻、流量、错误率、GC、连接池、下游 RT、变更记录,画在一条线上。第 4 章"线程多 CPU 低"、第 6 章"P99 尖刺对 GC 事件"、第 7.3 章"连接等待超时"的判断,全部来自这种对齐。相关性先于因果:时间轴上同时动的两条线,就是最好的下钻入口。

排错决策树

假设驱动,不是漫游驱动

证据在手后进入诊断循环:假设 → 最小代价验证 → 结论/新假设。"可能是缓存穿透"就去查缓存命中率曲线,而不是顺手把缓存 TTL 改了看看。每个假设配一个可证伪的观测动作,失败照样有信息量(排除了一个方向)。排错中最贵的状态是"漫游":没有假设地翻代码、凭印象改配置——第 8.2 节的翻车现场在故障里同样上演。

JVM 侧的取证清单按症状索引(本册各章的浓缩):

  • OOM:dump + MAT 支配树(第 6.1 节四步法)
  • 长停顿/尖刺:GC 日志对时间轴,看 Full GC 与谷底(第 6.2 节)
  • hang/死锁:jstack 的自动检测段、BLOCKED 线程的持锁(第 5.2 节)
  • 诡异类错误:类加载日志看版本来源(第 6.3、7.2 节)
  • 数据错乱:先查共享可变状态与静默吞掉的异常(第 3.1、5.1、5.4 节)
  • 连接/超时:池的饱和度与借出时长(第 7.3 节)

第二幕:复盘是把事故变成资产

止血与修复完成,才是真正决定团队水平的环节。低质量复盘的标志:根因写"代码考虑不周",改进项写"加强测试、下次小心"——不可执行、不可验证、不可防止重犯。高质量复盘用五问法(对每个直接原因连问五次为什么)挖到系统性层:

现象:支付回调丢失三天 为什么1:异常被空 catch 吞了(直接原因 第3.1节) 为什么2:紧急上线时为了先恢复服务加了绕过 代码走查没发现 为什么3:代码评审对空 catch 没有硬性检查项 为什么4:评审清单本身没有"异常处理"条目 为什么5:故障驱动的经验从未沉淀为清单 团队每次从零学 系统性根因:缺防坑清单制度 改进项:建立评审清单含异常处理硬条款 CI 静态扫描空catch 告警

五问的方向要对着系统与流程问,不是对着人问——"他为什么犯错"的终点是追责,"什么系统让人容易犯这个错"的终点是改进。改进项的验收标准:可执行(有 owner 与截止日)、可验证(怎么算做完)、面向制度(工具、清单、流程,而非"细心一点")。

复盘模板(可直接搬进 wiki):

  1. 时间轴:告警、发现、决策、止血、恢复的关键时刻(含犹豫点)
  2. 影响面:持续时间、受损业务量、资损口径
  3. 根因链:五问法的完整链条,直接原因到系统性根因
  4. 幸运因子:哪些环节靠运气没扩大(没打到大促、值班同学恰好懂 jstack)——幸运因子是防线的漏洞清单
  5. 改进项:制度层/工具层/代码层各若干,含 owner 与验收标准
  6. 归档:关联到本册对应章节的知识点,新人培训案例库

故障后的"机会窗口"稍纵即逝:痛感最强的一周内把清单与扫描规则落地,三个月后同样的痛就只剩财务数字了。这也是本册反复出现"防坑清单"的原因——每节的清单合起来,就是一份从 76 篇旧文档与几十次事故里蒸馏出来的 Java 生产防线

⚠️ 常见坑:复盘变追责会。一旦会议的产出是"谁背锅",下一次故障的第一动作就从"报证据"变成"藏证据"——信息流通断了,团队免疫力的根基就断了。 blameless 不是不严肃,是把严肃用在系统上。

💡 关键直觉:事故是系统免费寄来的渗透测试报告。复盘中唯一真正的失败,是让同一份报告寄来第二次。

防坑清单

  • 止血优先:回滚不需要理解根因;重启前先取证三件套
  • 时间轴对齐是第一分析动作,找同时动的曲线
  • 假设驱动排错,每个假设配最小验证;禁止无假设漫游
  • 复盘五问向系统问,改进项可执行可验证
  • 每次故障沉淀清单与扫描规则,一周内落地

本节要点回顾

  • 两幕结构:现场(止血/取证/观测三流并行),事后(根因与制度)
  • 取证三件套:jstack、dump、jstat——重启前抢救的案发现场
  • 决策树:变更先回滚,资源形态分流(阻塞/热点/排队/错误聚类)
  • 五问法:对着系统问到底,改进项落在清单、工具、流程
  • 资产化:事故报告 + 检查项 + 新人案例库,防线随每次故障变厚

全书至此收束。回头看,从 Integer 缓存到复盘制度,一条主线贯穿:Java 的坑源于语言默认行为与生产规模的错配,而防线的本质是把每一次错配变成显式的、可检查的约定。愿你的下一个深夜告警,十分钟内就能在这册书里翻到那一页。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U