知识卡片

面对完全陌生的问题:先用减法策略缩小范围,再回头理解原理

结构图卡

内容

排查问题时最棘手的一类场景是unknown-unknown——问题产生的原因超出了自己原有的知识体系(比如某个JVM内部的Bug、某个从没听过的内核特殊机制),这类场景容易让人产生焦虑,误以为”这个问题不科学、无法解决”,进而陷入反复检查日志、反复重启这类没有实质价值的动作,甚至开始论证”这个问题不可能发生”。核心认知误区在于:超出已有知识体系,不等于无法分析——面对这类问题,虽然没有具体、现成的方法,但有一套通用思路可以遵循:先做减法,尽可能缩小问题的范围,等范围变得可控之后,再去深入了解相应的原理。具体手段包括:尝试重现问题(通过测试环境压测、TCPcopy复制流量、或者保留现场等方式让问题变得可复现、可反复观察);对比正常系统和异常系统之间的具体差异,找出真正的异同点;通过已有知识排除掉异常表现里那些其实是正常的部分,从而缩小真正异常的范围;最后通过看书、教程了解相关原理,或者直接看源码了解具体实现机制。一个真实案例完整展示了这套流程:Tomcat请求突然变慢,日志没有异常、性能没有明显瓶颈、线程数正常,常规工具也找不到新线索——先尝试复现问题(测试环境压测、TCPcopy或保留现场),复现后用TCPdump和系统调用跟踪梳理出一次调用的完整时间轴,发现时间浪费在TCP三次握手和Accept之间这个窄范围里;再顺着”Accept”这个关键字去查Tomcat源代码,最终定位到一个真实Bug:在bio方式下,如果应用发生StackOverflow,线程会退出,但连接计数没有被相应减掉,导致新请求无法被正常Accept(这个Bug存在于Tomcat 7.0.42之前的版本)。

结构图

flowchart TB
    A["遭遇完全陌生的问题\n(unknown-unknown)"] --> B{"是否陷入焦虑?\n反复重启/反复查日志"}
    B -->|"是(误区)"| C["浪费时间且无实质进展"]
    B -->|"否(正确路径)"| D["第一步:尝试重现问题\n(压测/TCPcopy/保留现场)"]
    D --> E["第二步:对比正常与异常系统\n找出真正差异"]
    E --> F["第三步:用已有知识\n排除表现中的正常部分\n持续缩小异常范围"]
    F --> G["第四步:范围可控后\n查书籍/教程/源码理解原理"]
    G --> H["定位真正根因"]
    subgraph 案例["Tomcat慢请求真实案例"]
        I["TCPdump+系统调用跟踪梳理时间轴"] --> J["发现耗时集中在\nTCP三次握手到Accept之间"]
        J --> K["按Accept关键字查Tomcat源码"]
        K --> L["定位Bug:bio下StackOverflow\n线程退出但连接计数未减\n(7.0.42之前版本)"]
    end
    D -.-> 案例

参考来源

- 位置:《高可用架构(第1卷)》第5章《运维保障》"5.4 微博在大规模、高负载系统问题排查方法"节,"5.4.2 排查方法及线索"(源文件:_epub-src/OEBPS/Text/Chapter5_4_3.xhtml) - 结论依据:原文说明"这里其实有个误区,超出知识体系并不意味着不能分析问题……可以做减法,尽可能缩小范围,当范围可控之后,再去了解相应的原理",并给出Tomcat案例的完整排查过程("尝试复现问题……用TCPdump和接跟踪了网络包状况和系统调用……发现时间浪费在三次握手和Accept之间……通过Accept关键字在Tomcat源代码中查找……找到了Tomcat的一个Bug"),直接支撑本卡片结论与结构图。 - 原始内容:这里其实有个误区,超出知识体系并不意味着不能分析问题……可以做减法,尽可能缩小范围,当范围可控之后,再去了解相应的原理……通过Accept关键字在Tomcat源代码中查找,分析了Accept相关的代码,找到了Tomcat的一个Bug。