一、问题排查的底层逻辑
1.1 什么是发散问题?
先说说我自己的理解。发散问题,说白了就是那种「你明明觉得问题出在这里,查了半天却发现根本不是」的坑。
举个例子。有一次线上服务突然变慢,我第一反应是数据库扛不住了。结果一查,CPU、内存、IO 都正常。那是不是网络问题?也不是。最后发现,是某个同事上线了一个新功能,日志打印得太疯狂,把磁盘写满了。你看,一个性能问题,查到最后变成了磁盘问题——这就是典型的发散。
发散问题的特征其实很清晰:
- 表象和根因不在同一个层面——比如用户报错是 502,根因可能是 DNS 配置错了
- 排查路径会不断分叉——你查 A,发现 A 没问题,又得去查 B,B 也没问题,再去查 C...
- 信息越多,越容易跑偏——我见过有人查了三天,最后发现是某个配置文件少了个逗号
核心观点:发散问题的本质,是「因果关系链断裂」或「因果关系链过长」。你看到的症状,和真正的病因之间,隔了好几层间接关系。
1.2 为什么问题会发散?
这个问题我琢磨了很久。后来发现,原因其实就三个:
- 系统太复杂——现在的系统,动不动就是微服务、分布式、多机房。一个请求经过十几个服务,每个服务都可能出问题。你想想看,这排查起来能不发散吗?
- 信息不对称——你看到的日志、监控、告警,都是别人设计好的。但设计这些的人,可能根本没想过你会遇到这种问题。我在项目中遇到过,某个中间件的日志级别默认是 WARN,结果关键的错误信息被吞了,查了两天才发现。
- 人的认知偏差——这个最要命。我们总是倾向于相信自己熟悉的方向。比如你是做数据库的,遇到问题第一反应就是查 SQL。但问题可能根本不在数据库。
避坑指南:我曾经因为「经验主义」吃过亏。一个接口超时的问题,我凭经验觉得是连接池不够,结果调大连接池后问题更严重了。后来才发现,是上游服务把超时时间设得太短,根本不是连接池的事。
1.3 排查问题的核心思维模型
好了,既然问题会发散,那我们怎么应对?我个人的习惯是,用三个思维模型来「收束」问题。
1.3.1 5W2H:把问题说清楚
很多问题查不下去,是因为一开始就没定义清楚。5W2H 就是帮你把问题「框住」的。
| 维度 | 问题 | 示例 |
|---|---|---|
| What | 发生了什么? | 接口返回 500 错误 |
| Why | 为什么认为是问题? | 影响了用户下单 |
| Where | 在哪个环节? | 订单服务 / 生产环境 |
| When | 什么时候开始的? | 10:15 分,持续了 5 分钟 |
| Who | 谁影响的? | 所有用户 / 特定用户 |
| How | 怎么发现的? | 监控告警 + 用户反馈 |
| How much | 影响范围多大? | 影响 200 笔订单 |
我建议,每次接到问题,先花 5 分钟把这张表填完。填完之后,你会发现排查方向清晰很多。
1.3.2 MECE:不重不漏地拆解
MECE 是「Mutually Exclusive, Collectively Exhaustive」的缩写,意思是「相互独立,完全穷尽」。说白了,就是把所有可能的原因列出来,而且这些原因之间不能有重叠。
举个例子。接口慢,可能的原因有哪些?
- 客户端侧:网络慢、DNS 解析慢、客户端代码问题
- 服务端侧:CPU 瓶颈、内存瓶颈、IO 瓶颈、锁竞争、代码逻辑问题
- 中间件侧:数据库慢、缓存慢、消息队列慢
你看,这样一分,每个方向都是独立的,而且覆盖了所有可能。排查的时候,按顺序一个个排除就行。
小技巧:MECE 拆解的时候,可以用「二分法」来辅助。比如「是客户端问题还是服务端问题?」「是硬件问题还是软件问题?」「是代码问题还是配置问题?」。每次二分,都能快速缩小范围。
1.3.3 因果链分析:找到真正的根因
这个是我最常用的方法。因果链分析,就是顺着「现象 → 直接原因 → 间接原因 → 根因」这条线往下挖。
我画了一张图,帮你理解这个链条:
嗯,这里要注意。因果链分析最忌讳「想当然」。比如上面这个例子,如果你查到「数据库连接池满」就停了,那你就只解决了表面问题。真正的根因是「缺少索引」,不加上索引,下次还会出问题。
我个人的习惯是,每找到一个原因,就问自己三遍「然后呢?」,直到问不出为止。这时候,你大概率已经找到根因了。
总结一下:
- 5W2H:把问题定义清楚,避免跑偏
- MECE:把所有可能的原因列出来,不重不漏
- 因果链分析:顺着链条往下挖,找到真正的根因
这三个模型不是孤立的。我一般先用 5W2H 定义问题,然后用 MECE 拆解可能的原因,最后用因果链分析逐个深入。一套组合拳下来,大部分发散问题都能收住。
好了,这一章就到这里。记住,排查问题不是靠运气,而是靠方法。把底层逻辑搞清楚了,后面的事情就顺了。