排查问题的顺序,比懂多少工具重要
一、先分类,不要先动手
出问题时最容易犯的错是先猜原因再验证。猜错了会走很远,而且因为已经投入了时间,不愿意回头。
正确做法是先给现象分类,不同类别走不同的排查路径。
一、必现还是偶发。 必现的问题最好查,能稳定复现就一定有确定的原因。偶发的问题要收集现场信息。
二、能不能稳定复现。 能,就写个最小复现用例,把排查范围从整个系统缩到一个页面甚至一个方法。不能,就得先加日志收集信息。
三、影响范围。 全部用户、部分用户、特定环境(只在小程序、只在某台机器、只在测试环境)。范围本身就是重要线索。
二、复现之后的第一步:二分
用二分法定位,不要从头读代码。
最有效的一个操作是注释掉一半再测:
// 怀疑是 A 和 B 交互导致的,先只留 A
const result = stepA(input);
// const result = stepB(stepA(input));
测试结果如何,直接砍掉一半搜索空间。重复几次就能定位到具体几行。
版本二分更好用。 如果知道"上个版本还好",那就专门看两个版本之间的 diff 范围,比在几十万行代码里读要高效得多:
git log --oneline v1.2.0..v1.3.0
三、偶发问题的关键是先拿到现场
偶发问题没法复现时,唯一出路是在用户出问题的那一刻把现场信息记下来。
一、错误上报。 捕获全局错误,把堆栈、用户操作路径、页面参数、浏览器信息一起发到收集服务。堆栈只有第一行通常不够看,压缩过更不够,所以要配 source map。
二、关键状态快照。 在执行关键操作前后,把相关变量记进日志。
try {
const result = await submitOrder(form);
return result;
} catch (err) {
logger.error('submit 失败', { form, err, ts: Date.now() });
throw err;
}
注意变量要脱敏。
三、关联标识。 前端生成一个 trace id,请求带上,后端日志里也记。排查时用这个 id 把前后端日志串起来,没有它就只能靠时间猜。
四、工具的顺序
一、浏览器端的问题先看 Network 面板。 请求发出去了吗、状态码是什么、耗时多久、返回体长什么样。这一步能排除掉大半问题,而且不花时间。
二、再看 Console。 有没有报错、警告。跨域报错、证书问题、语法错误都在这里。
三、后端问题先看日志。 按 trace id 搜,前端拿到的错误信息里通常带得上。
四、数据库问题开慢查询日志。 很多"接口慢"最后定位成一条没走索引的 SQL。
五、工具的顺序是:grep 搜日志 → 复现 → 二分 → 读代码。不要一上来就 debug 单步,单步在异步和第三方调用多的代码里几乎没有效果。
五、记录排查过程
问题解决了,不代表排查结束了。 如果不记录,下次同样问题还要再走一遍。
值得记下来的三样东西:
一、真正的根因。 注意不是表面上那个报错的代码,是为什么它会收到错误的输入。
二、定位路径。 哪一步开始怀疑、哪个操作否定了猜测。这段下次能省最多时间。
三、防止复发的动作。 加了什么校验、改了什么监控、哪个测试用例补上了。
第四样是暂时不要的: “下次注意”。这句话没有任何可执行内容。
六、一个心态上的提醒
排查的时间压力下,人容易在找到第一个可疑点时就停下。经验上第一个可疑点经常不是根因,只是症状。
问自己一句:如果这是这个原因,那为什么只在某些情况下发生? 如果这个问题指向的现象解释不了,那当前的猜测大概率是错的,继续往下挖一层。
- 点赞
- 收藏
- 关注作者
评论(0)