线上问题最消耗时间的阶段,通常不是修复,而是所有人同时提出解释:可能是网络、可能是缓存、可能是刚上线的版本。每个猜测听起来都合理,但它们没有帮助团队更接近事实。

有效排障的目标不是尽快证明自己正确,而是用最低成本淘汰错误解释。

第一步:把现象写成可以证伪的句子

“页面很慢”无法直接验证。把它改写成:

版本 3.4.0 中,Android 14 用户首次进入详情页时,P95 可交互时间从 1.2 秒上升到 3.8 秒;二次进入没有明显变化。

这句话给出了版本、平台、触发条件、指标和对照组。范围越清晰,后续需要检查的变量越少。

第二步:建立统一时间线

把关键事件放在同一条时间轴上:

10:02  版本开始灰度 5%
10:07 API P95 保持稳定
10:11 客户端首屏耗时告警
10:14 图片 CDN 命中率下降
10:18 停止扩大灰度

相关性不是因果,但时间关系可以快速排除不可能的解释。发生在现象之后的变化,不可能是它的起因。

第三步:一次只改变一个变量

好的实验会让结果变得有区分度。例如:

  • 关闭新版本中的图片预取,其他配置不变;
  • 对同一请求分别使用命中和未命中的 CDN 节点;
  • 用同一设备对比首次进入和清理缓存后的再次进入。

如果一次同时回滚三个功能,即使问题消失,也无法知道真正起作用的是哪一个。

第四步:主动寻找反证

确定一个假设后,先问:“如果它是错的,我应该看到什么?”

假设图片解码阻塞主线程,那么低分辨率图片应该显著降低卡顿;如果替换图片后指标完全不变,就应降低这个假设的优先级。反证能避免团队在一个看似顺手的方向上投入过多时间。

第五步:修复之后补上护栏

一次故障至少应该留下其中一项长期资产:

  • 一个覆盖关键路径的自动化测试;
  • 一项能更早发现变化的指标或告警;
  • 一段可以重复使用的诊断脚本;
  • 一份包含触发条件与决策记录的复盘。

否则,相同问题只是被延期,而不是被解决。

一张随手可用的检查清单

[ ] 现象是否包含范围、指标和对照?
[ ] 近期变更是否已按时间排列?
[ ] 当前实验是否只改变一个变量?
[ ] 假设是否有明确的反证条件?
[ ] 修复是否解释了全部已知现象?
[ ] 是否补上了测试、观测或文档?

排障不是灵感竞赛。它更像一套压缩不确定性的工程流程:每一步都让可能性变少,让证据变多。