1. 故障复现的哲学

做故障排查这么多年,我见过太多人一上来就翻日志、查监控、改代码。忙活半天,问题没找到,反而把现场搞乱了。你想想看,这像不像一个侦探到了案发现场,二话不说先把脚印擦了?

故障复现,就是那个「保护现场」的动作。它不是什么高深理论,而是整个排查工作的地基。地基不稳,后面全是白搭。

为什么非要复现?

说白了,不复现的排查就是瞎猜。我遇到过不少团队,线上出了故障,看一眼错误日志就断定是「内存泄漏」,然后开始加参数、改配置。结果呢?问题照旧。为什么?因为那个日志可能是另一个无关问题留下的。

复现能帮你做到三件事:

  • 确认问题真实存在——有些告警是误报,有些是偶发,不亲手复现一次,你连对手是谁都不知道。
  • 锁定触发条件——同样的代码,为什么今天崩明天不崩?复现能让你找到那个「开关」。
  • 验证修复是否有效——改完代码,跑一遍复现步骤,问题没了,这才叫修好了。否则你只是在赌。

核心观点:不复原,不诊断。这是故障排查的第一条铁律。

复现的三大原则

我这些年总结下来,好的复现流程必须满足三个条件:可观测、可控制、可重复。缺一个,复现就是白做。

1. 可观测(Observable)

复现过程中,你得能「看见」故障的发生。看不见,就等于没发生。

什么叫可观测?我举个例子。有一次线上服务频繁超时,我让团队先加全链路追踪,把每个接口的耗时、调用栈、数据库查询都打出来。然后才去复现。结果发现,超时都卡在同一个 Redis 操作上——那个操作没设置超时时间,连接池被占满了。

如果没有这些观测手段,你只能看到「服务慢」,根本不知道慢在哪。

可观测的手段包括:

  • 日志——结构化、带时间戳、分级别
  • 指标——CPU、内存、QPS、延迟分位数
  • 链路追踪——一次请求经过的所有服务节点
  • 事件记录——配置变更、发布、回滚等操作

我的习惯:在复现之前,先问自己一句——「如果故障发生了,我能不能从数据里看出它从哪开始?」如果答案是否定的,先补观测手段,再动手复现。

2. 可控制(Controllable)

复现不是碰运气。你得能主动控制环境、流量、数据,让故障按你的意愿出现。

我记得有一次排查一个内存泄漏问题。线上环境 8 小时才触发一次,根本没法调试。后来我写了个压测脚本,把请求量放大 10 倍,同时把 GC 日志打开。结果 20 分钟就复现了。为什么?因为我控制了流量和观测开关。

可控制的关键要素:

控制维度 说明 常见手段
环境 与生产环境一致或可模拟 容器化、配置管理、混沌工程
流量 可调节请求量、并发数 压测工具、流量复制
数据 可构造特定数据集 脱敏数据、边界值构造
状态 可重置到初始状态 快照、数据库回滚

避坑指南:我曾经在复现一个死锁问题时,忘了控制数据库连接池大小。结果复现了 10 次,只有 3 次出现死锁。后来把连接池固定到和线上一样,才稳定复现。控制不到位,复现率就不可信。

3. 可重复(Repeatable)

一次复现可能是巧合。两次复现可能是运气。三次以上,你才敢说「我找到规律了」。

可重复意味着:你写下一份清晰的复现步骤,交给另一个人,他照着做,也能看到同样的故障。

我见过最糟糕的复现文档长什么样?「先跑一下,等一会儿,可能就崩了。」——这哪是复现步骤,这是许愿。

好的复现步骤应该是:

  1. 准备环境:操作系统版本、依赖库版本、配置参数
  2. 准备数据:数据库初始化脚本、测试数据文件
  3. 执行操作:具体的命令、请求参数、操作顺序
  4. 验证结果:预期现象、日志关键字、监控指标阈值

一个简单的检查标准:如果你的复现步骤里出现了「可能」「大概」「有时候」这些词,说明它还不够可重复。

三大原则的关系

这三个原则不是孤立的。它们像三条腿的凳子,缺一条就站不稳。

  • 可观测让你知道「发生了什么」
  • 可控制让你知道「怎么让它发生」
  • 可重复让你知道「它一定会发生」

只有三者都满足,你才能从「偶然遇到」变成「主动掌控」。

故障复现三大原则关系图 故障复现 可观测 可控制 可重复 三条腿缺一条,复现就站不稳 可观测 → 看见故障 | 可控制 → 触发故障 | 可重复 → 验证故障 三者共同构成可靠复现的基石

一个真实的复现案例

讲个我亲身经历的事。有一次线上支付服务间歇性返回 500 错误,频率不高,大概每小时出现几次。团队查了两天没头绪。

我接手后,先做了三件事:

  1. 加观测——在支付接口的入口和出口都打了详细日志,记录请求参数、耗时、异常栈
  2. 控环境——从线上拉了一台机器,复制了同样的流量比例和数据库状态
  3. 找规律——用流量复制工具把线上请求回放,同时观察日志

结果发现:每次 500 错误都发生在用户余额刚好等于商品价格的时候。代码里有个 if (balance > price) 的判断,等于的情况走了 else 分支,而 else 分支里有个空指针。

你看,如果没有可观测的日志,我找不到规律;如果没有可控制的环境,我无法隔离变量;如果没有可重复的流量回放,我可能永远等不到那个「刚好相等」的请求。

我的建议:每次接到故障,先花 10 分钟想清楚——「这个故障我能复现吗?如果能,怎么复现?如果不能,缺什么?」想清楚了再动手,比直接冲进代码里翻要快得多。

小结

故障复现不是浪费时间,恰恰相反,它是节省时间的最好方式。三大原则——可观测、可控制、可重复——就是你的检查清单。每次复现前,拿它过一遍,能帮你少走至少一半的弯路。

记住一句话:能复现的故障,已经解决了一半。