AI翻译:排查故障:永不过时的技能
下面是文章的中文翻译:
排查故障:永不过时的技能
来源链接: Troubleshooting: The Skill That Never Goes Obsolete
发布时间: 2025-02-22T03:22:00.000Z
我大部分工作,无论在哪个领域,都可以归纳为一项技能:故障排查。
我将故障排查定义为 系统性地找到系统中不期望行为的原因,并予以修复。
故障排查往往是在显性学习“这门技能”的过程中通过潜移默化学到的,鲜少把故障排查单独讨论为一门 独立的技能。但是,一个有效的故障排查方法中的许多特性都是不依赖于具体领域的。
认识到我花在 故障排查 上的时间比花在 构建 或 操作 上的时间还要多,而且故障排查这门技能可以独立于它所应用的领域来磨练,我决定尝试找出如何提高自己的排查能力 —— 从而在多个领域提升效率。
我平时的做法主要是抓耳挠腮,先把错误信息粘到 Google 上搜索,然后不断思索与测试假设来缩小搜索范围。但我经常发现自己重复犯着曾经犯过的错误。所以在进行故障排查时,我总会提醒自己以下几点,以保持思路清晰,避免走进死胡同。
第一步:退一步思考
故障排查需要一种特定的心态。就我所知,这需要对系统底层结构的兴趣 —— 用 皮尔西格(Pirsig)的术语来说 是一种“经典”的思维方式 —— 需要耐心、注重细节和顽强毅力。
有时,即使赶时间,慢下来、深思熟虑、冥想式地处理故障排查问题反而更有效。
很容易陷入不断地应急处理问题的状态,而忘了停下来 思考:这个问题的真正原因是什么?究竟 到底发生了什么?
故障排查者本身也是系统的一部分。因此,会有 探针效应 和著名的 海森堡式错误(heisenbug) 。
确保你在调整正确的“琴弦”
玩吉他一段时间的人都能体会到那种直观的感觉:突然发现自己正在调那根自己并没在拨的琴弦。难怪怎么弄都没用!
在试图修复系统之前,我会做一件 绝对能产生效果 的事情。
如果我认为自己知道该切断哪根线,我会先拉一下看看另一头是否有反应。
当我在排查 CSS bug 时,我经常先设置 * {color: red !important;}
,以确保 我写的代码在正确的文件中,并且真正在运行!
确定各个流程
花大量时间去“修复”问题其实并非最难的部分,容易修复的往往不是问题所在。困难在于理解整个 系统,然后隔离并理解问题。
我通常先从“东西”(电、 水、汽油、空气、压力、数据、污水或其它)在系统中是如何流动,并在过程中转化为不同的“东西”进行思考开始。
输入、输出是什么?在过程中转化发生了什么?流经系统的不同“东西”是否可以分成几个半独立的子系统?
在电气系统中,实际追踪线路通常有帮助;在机械系统中,同样适用于承载液体或气体的管道,或传递机械力的控制电缆、凸轮、齿轮、链条等。在软件中,则是追踪数据流。在社会动态中 —— 祝你好运!
观察症状
这里 本应 发生什么,实际上又发生了什么,两者之间有何不同?
如果可能,我会根据症状缩小 问题可能影响的子系统范围。如果我的车的刹车灯不亮,问题可能在于电气;如果车下有油渍,则很可能 不是 电气问题。如果发动机无法启动,则可能是两方面的原因,都需要进一步调查。
认为自己“完全理解”系统往往反而成为故障排查的障碍。 即使我“对系统了如指掌”,也不可能完全理解它。即使是我亲自构建的系统,其中也包含了我未曾参与设计的部分;即使看似简单的系统,其复杂性也是无限的。(正如卡尔·萨根所说:“如果你想从零开始做一个苹果派,你得先发明整个宇宙。”)
隔离问题
接下来的步骤是找出该子系统在哪个环节失败了。
我的基本做法是:对系统进行“科学实验”。
-
就问题形成一个假设。 这个假设可能是从症状中直观获得的第一印象,也可能是经过长时间观察后的最佳猜测。
- 先排除最简单和最可能出问题的区域。 那些该定期检修、曾经出故障过或容易受机械压力影响的部件。好的系统往往会设计得易于维修。例如:电气系统中的保险丝和断路器、皮带和链条、过滤器、各类接头以及输入/输出设备。
- 如果没有简单的方法判断问题出在哪个部分,那就进行一种非正式的 二分查找 。
-
找出验证假设的最简单方法。 通常,这意味着“切断”我认为问题出现之前或之后的系统部分,并在切断点测试其功能。
拆解子系统
如果可能,我会将正在调试的子系统断开。
这样做有三个好处:
- 它防止了与系统其他部分之间的奇怪交互,使得诊断过程不会因为干扰而变得复杂(一旦子系统自身正常工作,我可以再重新连接,观察其是否 依然 正常工作)
- 避免因自己的错误而牵连整个系统
- 往往能缩短反馈回路
或者不拆解
如果我无法(或不愿)完全拆解各个部分,另一种方法是在不同位置进行 探针测试 —— 或称为 “切断并探测”。
如果我知道或者能直觉地感知到在系统正常时某个测试点参数的可接受范围,那么实际测得的值就可以指示出问题所在的位置。
找到合适的“切断点”
在保持系统功能的同时,我最多能在多少个点上“切断”系统去进行测试?
火花塞就是子系统之间的一个切断点的例子。
如果发动机无法启动,但我能得到火花,那么问题很可能不在电气系统。
除了内部的切断点,我总是试着在我负责的系统与外部世界之间的接口处进行测试,这有助于我判断“我这边的东西”是否损坏,还是仅仅在尝试与“别人那边出问题的东西”交互时出现了故障(而后者可能并不在我修复权限之内)。试图修复并非故障的部分会浪费大量时间!
平衡获取信息与尝试修复
解决问题时,应花多少精力尝试修复与花多少精力获取问题信息之间如何平衡?
如果我的直觉正确,直接着手修复会快得多。
但如果直觉错了,系统性地收集信息从长远来看更加高效。
在进行故障排查时,我们往往带着一种关于问题 难易程度 的先验认知,这会影响我们什么时候直接跳进去修复,什么时候去获取更多信息。
但往往我们的“难易先验”是 错误的。因此,我们需要基于个人倾向和领域专长,形成一种元先验,来判断自己对问题难度估计的准确性。
了解问题的“赌注”
故障排查问题的风险范围从零(爱好软件项目)到改变人生(医疗诊断),甚至是生死存亡(通用人工智能、核武器)都有所不同,这会影响我们处理问题的方式。
因此,我会问自己:
-
最糟糕的情况是什么?如果我搞砸会带来什么风险?而且,我搞砸的可能性有多大?
- 对排查者的危险:这个系统工作起来有多危险?是否涉及高压、易燃材料、有毒化学品、摇晃不定的零件,或者数据丢失的风险?
- 对旁观者的危险:同上,但还要考虑影响半径、旁观者对危险的无知以及缺乏安全设备等因素。
- 对系统本身的危险:这个系统有多脆弱?是否可以替换?
- 对他人的危险:这个系统一旦表现不正常,会给下游用户带来什么后果?
-
修复与不修复之间的风险对比如何?
- 如果某个部分已经处于极度危险的状态,修复它相对来说更安全,即便修复本身也有可能失败。
-
这个系统归谁所有?
- 是我弄坏了这个系统吗?我有责任修复吗?
- 我是领薪水去修复它的吗?如果是,成功、失败、甚至灾难性失败的几率分别是多少,客户是否知晓风险?(我已经不再为那些没有备份系统的人提供志愿的技术支持。)
-
如何降低此次干预的下行风险?
- 通常来说,更慢、更谨慎地工作(以免再次搞砸);在“试验环境”而不是“线上系统”上作业;对系统进行备份。
这里的危险至少包含四个部分:时间框架、强度、传播范围以及物理性。最明显的危险是即时且物理上的。但从危害/收益的角度来看,在一家大型投资银行处理关键代码,从长远来看可能在物理上同样危险;只不过这种风险是分散的、延迟的、且看不见的。
- 爱好软件项目可能有长期的正面或负面风险,但短期内影响的人非常少,且这些人对其依赖不深,也不会因物理原因受到影响。
- 汽车刹车系统维修存在中等风险,但如果你弄砸,整个高速公路上的每个人(以及他们所负责的一切)都可能面临风险。
- 如果我的车在黄昏时分在治安较差的街区熄火了,临时凑合接上电池可能比四处找酒店和修理工来得更安全。
- 做医疗诊断对一个人来说风险巨大、可能改变生命,而处理医疗软件则关系到 更多人 的生命,风险虽然推迟但同样重大。影响外交政策或核战略可能会使全世界面临风险。
别想得太复杂
不要以为它很复杂。仅仅因为调试困难,并不意味着问题的根源就复杂。
但也不要以为它一定很简单。
保持耐心
不多说了。
获取关于系统的“信息”
从定义上说,故障排查者永远不可能通晓一切。优秀的排查者必须习惯于处在一种无知的状态里。
需要什么信息,以及如何获取,取决于系统和问题的具体细节。
知道对不同信息该用哪个搜索引擎
有时候(比如在机械领域或钓鱼失败时)我需要认识懂得如何操作的人,然后请他们帮忙,还得给他们买瓶啤酒。
而另一些时候,我需要知道如何使用各种手册或库。(案例:我母亲的 Subaru 车窗突然失灵,各路车修人纷纷出手,我检查了保险丝,但她却灵光一现,决定 仔细阅读 使用说明,而不是仅仅扫一眼保险丝相关的信息。原来是儿童锁的问题。)
在现代社会,我大部分时间需要懂得如何使用搜索引擎。不同的搜索引擎适用于不同目的,Google 似乎也不再索引许多小众网站。
有时我甚至需要一个大语言模型(LLM),因为我不知道该如何用正确的术语去描述我的问题,需要在专业论坛中搜索以过滤掉冗余信息,或是在 YouTube 上搜索有关那些难以用语言描述的实操技能,又或者直接查阅系统相关的文档或手册。
知道如何利用高级搜索条件缩小搜索范围
虽然这些技巧并非专门针对故障排查,但如果你不熟悉搜索操作,下面的三篇文章可以作为入门:
⇒ 如何在互联网上找到任何东西(以 Google 为例)
⇒ Google 搜索运算符:完整清单(44 个高级运算符)(Google 专用,更全面,带营销属性)
⇒ 互联网搜索技巧(详尽,学术取向)
知道如何扩大搜索范围并滤除无关信息
大多数系统都会发出各种各样的信息,而且相关性参差不齐。
在软件日志中,会有一大堆重复的废话,直到那一行话突然提醒我注意。通常,它会包含“error”或“fail”,或提到受影响的子系统。
同样,发动机会发出大量噪音。大部分噪音都是正常的,关键是要捕捉到预期噪音被扣除后剩下的异样声音——那就是问题的“声纹”。
错误信息中只有 部分内容 才真正重要。
大多数软件错误信息如果原样复制到 Google 搜索中,往往找不到太多有用信息,因为其中包含了 特定于我设备 的内容。我一般会从完整的错误信息中去掉显而易见的设备特定内容开始搜索。如果没有结果,我会扩大搜索范围,不再限制于 具体版本,也不再针对 具体硬件 或 特定软件 搜索,然后在论坛中找到使用不同设备、运行不同应用但依赖出问题相同依赖项的人。他们的修复方法可能不适用,但可能能指向问题所在。之后我便获取更多数据,再重复这个过程。
学会“钓鱼”
如果某件事需要修复,我可以试着自己动手,这可能既慢又低效;或者找个专家来做,这样会又快又简单。但请别人来解决问题的代价是:我学习不到多少。
如果我碰到一个排查问题,而我对该领域一窍不通,一个非常有效的做法是:
- 找到该系统/问题的领域专家
- 不要让他们 为我 修复,而是 让他们和我一起修复。
短期来看,这样既慢又可能不那么有趣,但能学到很多东西。下次或许我就能独立解决了。
这构成了一个连续体,从一端的 看着他们修复 到另一端的 自己修复而他们在一旁监督。我自己动手越多,对双方来说进程就越慢、越令人沮丧 —— 同时也更能促使我学习。
从系统中获取信息
我越是能从系统中获取信息,最好是在错误发生时就获取,那么情况就越好。
我会尽可能从系统中获取信息:更多的输出、更具体的输出、从系统更多的节点采集数据。
在软件中,这意味着日志记录,或者在进程运行时附加调试器。
在电子设备中,第一步通常是拿出万用表,到各个节点检查系统状态。
在机械方面(我不是很擅长),我注意到我的大哥通常会选择 开着引擎盖运转,一边密切观察,一边闻听排查。
Eric Barker 在《Plays Well With Others》中谈到相关话题。我们在读人方面往往很糟糕(即便我们自以为不是),而少数能提供帮助的方法之一就是以能不断获得更多信息的方式来与对方交流。实际上,“从系统中获取更多信息”也是科学验证过的测谎方法之一(谎言者最终会自相矛盾)。类似地:很多人能对复杂话题滔滔不绝,但两三个精准的问题能迅速区分真正的专家和那些仅仅为了表现自己而引用表面意见的人。
当我们在自我调试时,单单是试图从系统中获取更多信息(记录日志)的行为,有时就能解决问题。
直观感受系统的容差
有时在修复过程中,我们可能会意外地弄坏一些东西,或者因为某种原因注定无法避免这种情况。
不同材料有不同的容差。某些部件即使遭受一定损伤,也不会破坏系统的整体功能;而其它部分如果遭到同样对待,可能会导致整个系统失效。
对于实体事物来说,需要通过机械直觉来施加合适的力度,并理解哪些部分能承受损伤,哪些不能。比如,钻孔或密封件比外壳更为脆弱。
与系统保持良好关系
我发现:不喜欢自己计算机的人往往使用计算机效率不高;同样,不喜欢与人打交道的人很难从别人那里得到自己想要的,除非他们懂得隐藏自己的情绪。这听起来有些飘渺,但我认为欣赏那台“出问题”的系统的美以及它的复杂性,能使人成为更有成效的故障排查者。把系统当作敌人,就真的会把系统当作敌人来看待。
在我看来,敌人与 对手 是不同的。与系统进行友好的竞争,试图“在游戏中战胜它”,似乎不会妨碍故障排查。对手必须被尊重和理解,才能战胜。那种“该死的电脑不按我意愿办事”的心态是需要避免的。当你讨厌一个敌人时,会将其个性全部剥离,最后只剩下一个夸张的影子;而你无法排查一个影子,因为它与真实系统不相符。
举个例子,我认识的两位本地机械师:其中一位经常咒骂、捶打工具,甚至会把工具乱扔,人们给他起了个绰号叫“愤怒的【姓名已隐】”。他是那种费用低廉的机械师。另一位则讲述自己曾用胶带和丝袜修复丰田的经历。无论我对他们的看法如何,大家都尊重他作为技师的技能。与他交谈时,他总显露出对汽车的热爱,并乐于与汽车打交道。他被认为是当地最好的机械师,自然也最贵。
利用现有资源
拥有正确的工具进行测试、拆解、修复和组装系统固然有帮助。
但在实际工作中,更重要的是能够随机应变,通过对事物内在结构的理解,找到合适的工具和替换部件,而不是拘泥于标签或先入之见。
缩短反馈周期
为了解决系统问题,我需要能够重现该问题。为了获取足够多的信息以可靠地重现错误,我往往需要在不同条件下运行系统多次。然后,一旦能够重现问题,还需要再次进行大量测试,每次调整参数,试图找出究竟是哪些条件 具体方面 触发了错误。
有时候,系统自带某种延时或滞后,这使得在没有一套复杂步骤的情况下很难重现错误。
遇到这种情况时,我会问:“有没有办法缩短这个反馈周期?”
在代码中,可能是将硬编码的超时时间调短,只专注于子组件(用虚拟输入输出)进行测试,局部运行避免网络延迟,启用热重载,或者自动化部署流程。
在电子设备中,可能只需将万用表直接贴在测试点上。
一个有点尴尬的例子:在故障排查时,我常常发现自己不得不在信号较慢的小手机上查资料,或者在我正在修理的对象与获取资料的设备间反复切换。把说明书或电脑放到工作的区域旁边,会节省不少时间。
降低噪音干扰
在进行任何干预前,我会尽量减少系统中那些混杂的变量和“杂音”。
断开子系统有助于这一点,因为与其他子系统间的相互作用可能会干扰测试结果。
缩短反馈周期也有帮助,因为时间延迟会为其它变量在输入与输出之间影响系统状态留下余地。
记录过程
写作常被认为是“思考的过程”。以下是我利用写作作为故障排查工具的两种方式:
-
像专业人士一样“橡皮鸭调试”:有时我只需草拟一篇论坛帖,却不发出去,就能解决问题。为了不显得愚笨,我必须把系统和问题的关键细节理清,这所耗费的心力往往比当时我真正寻求帮助时要多。结果是:发帖时如果不想显得自己没做功课,往往会花费超出预期的时间和精力来解决原本看似简单的问题。
-
留下线索轨迹:我发现,无论是写作还是画图,对很多故障排查项目都很有帮助,但对于需要多次会话才能解决的问题,这一点尤为关键。我往往会高估自己记住上下文的能力以及多久能重新启动项目的时间。于是我会建立一个故障排查笔记文件,无论当时的信息看起来多么显而易见或不完整,都能为下次找到问题留下痕迹。(我曾经在一次故障排查中逐字重复整个过程、找到问题——随后才意识到多年前我已经排查过这个 完全相同 的系统,并得出相同结论;只是当时由于过于仓促,没及时订购或安装新部件。)
通过投放极为详细的特定信息来观察“黑箱”的反应
尽管“断开子系统”是一个好建议,但有时我必须对那些黑箱系统进行故障排查。一种方法是向它们输入 非常特定 的数据,看其如何响应。如果系统对特定输入条件失败,可以尝试以下两种方法之一:
-
获取导致失败的条件/输入,依次移除 其中的一个组成部分,并输入到系统中。如果问题仍然出现,就再移除另一项(可选择恢复前一项),反复操作直至剩下的仅是 真正导致问题的因素,或者尽可能接近它。
-
选取一些确认无误、系统正常时的条件/输入,加入一个在故障输入中出现的因素,重复(单独或叠加加入)直到系统失败。
理解问题
也许是某个零件烧坏了。但问题在于 为什么它会烧坏?难道零件在周二下午烧坏是正常现象吗?或者,是短路、水浸、散热问题,或者(就像最近的一个案例中)受到附近雷达干扰而造成的失效?
如果某个东西按理说不应该失效,但却失效了,那么问题的背后必定还有其他原因。
在更换新零件前,我必须确信它不会重蹈覆辙。之前的零件可能本身规格不足,或者系统中还有其他东西让它承受了过大的负荷。
修复问题
一个被理解的问题基本上就已经解决了,除非零件稀缺或安装十分困难。
“修复”通常就是指“更换损坏的部件”。
我对问题以及系统的理解程度决定了需要更换整个系统的多大部分。有些人会贬称只会大面积更换零件的技师为“零件更换工”。总体来说,故障排查者越优秀,更换的部件往往越小。
这几种情况都有可能同时成立:
- 这个音响系统坏了。
- 这个 MP3 播放器坏了。
- 这个 MP3 播放器的耳机插孔坏了。
- 这个 MP3 播放器耳机插孔的焊点坏了。
我可以更换整个 MP3 播放器,也可以只更换耳机插孔,或者仅仅重新焊接那个焊点。结果都是一样的。
虽然更换超过必要范围的部件既浪费又不优雅,但优秀的故障排查者也必须知道在什么时候 放弃 深究那些并不重要的问题,而接受一种更节省资源的“创可贴”式解决方案。
故障排查技能能否传授?
自 2024 年 5 月以来,我断断续续地在写这篇文章。也许我自欺欺人,但我感觉自己的故障排查能力确实有所提升。最大的变化是 现在我开始主动面对问题。我开始接手那些平时并不吸引人的故障排查任务——纯粹为了验证我的理论,无论我是否觉得这些问题值得花时间去解决。而且,由于花了大量时间去思考和讨论故障排查,我觉得自己 应该 成为当地的某种专家,并且无论这种声誉是否只是我自我认同,都希望能当得起它。
如果有经费支持,我会用科学方法来验证。我会招募一批人,其中一半会阅读这篇文章,而另一半则阅读一篇长度和风格相当,但不是关于故障排查的文章。然后,两组人会在类似 sadservers.com 的网站上尝试解决 Linux 服务器的故障排查难题。哪一组会更有效率?如果阅读了这篇文章的人表现更好,这个实验可以在其它领域重复,看故障排查技能的通用性如何。(我也曾考虑过一个更有趣而不那么严谨的可能性:向 Wired 杂志提案,写一篇以故障排查建议为基础,针对我那些尴尬领域内无法自拔的故障排查案例的游记。)
结论
一旦我进入故障排查的心态,大部分事情都会被看作是故障排查问题。用这种系统—问题—解决的视角看待世界,在某些情况下是有效的,但这并不是看待世界的唯一方法,也未必适用于所有情境。
当我意识到自己正在面对故障排查问题时,并能有意识地去排查,能节省大量时间。但同样重要的是,也要清楚并非所有问题都需要解决。
下面是我在网上看到的一些故障排查的故事:
祝故障排查顺利!
当我让一个 Llama3 大语言模型 “列出这篇文章中的所有拼写、语法以及逻辑错误” 时,它列出了一堆真有的和幻觉出来的错误,包括“过于简化复杂系统(例如摩托车)”,并总结道:
总的来说,尽管这篇文章试图为故障排查提供一些指导方法,但由于存在大量错误,使其清晰性和有效性大打折扣。
但也许 你 能帮我查查这篇文章的问题:有没有我遗漏的关键技术?有没有你认为不靠谱的部分?欢迎留言或 发邮件 告诉我。
感谢所有在文章早期草稿阶段提出反馈的人,或与我花数小时讨论故障排查的人。所有错误均为我本人所致。
特别感谢我的大哥们,他们允许我使用那只著名的糖果盒,里面装满了捡来的电子元件;和我一起制作范德格拉夫发电机、摩斯电报、气动纸球射击器、海藻炮、自动机器人、火箭和点焊机;以及让我在十岁时(当时我还是充满希望地)写下“今天我学会了 PHP!!!”的日记。
以上即为该文章的完整中文翻译。