本篇要回答的问题:故障来了,正确的处理逻辑是什么?如何把故障排查从"靠运气和经验"变成一套可学习、可传授的系统化方法论——以"假设-验证排除"循环为核心,靠日志找到根因?
承接上一讲的故障域与预案。本讲回答"发现故障之后怎么办":先讲一个反直觉的优先级(先恢复、后归因),再借作者从 WPS 的 IO 工作经历说明 SRE 事务工作的价值,最后给出通用的故障排查方法论。
写在排查之前:先恢复,后归因
关键判断:正确逻辑不是当场把问题修好,而是用最快方式让问题缓解或消失——SRE 核心考核常含季度/年故障率,磨蹭的恢复可能直接葬送年终奖。
故障恢复手段按初判选择:
| 故障原因初判 | 及时恢复手段 |
|---|---|
| 软硬件环境升级引入 | 版本回滚 |
| 用户请求导致负载过高 | 扩容;扩容无效则服务降级(关非核心功能/主动抛弃部分请求) |
| 软硬件环境本身故障 | 流量切换,导向无问题的任务实例 |
不要"故障驱动"——SRE 应居安思危、主动出击,例行检查服务入口指标,未触警告线的异常波动也要排查(像医生定期诊断),且例行排查要有结论、有应对方案。
SRE 是极好的工作(作者的 WPS/IO 经历)
作者实习首个任务是 WPS 的存盘读盘(IO),看似事务性,实则极核心:
| 看似无聊 | 实则核心 |
|---|---|
| 把变量写盘再读出 | 用户文件是办公软件最重要资产(MFC 序列化的版本不兼容=抛弃用户) |
| 不做具体功能 | 数据是软件的灵魂——研究数据结构是了解软件设计思想最快的路 |
| 边缘任务 | “业务功能是点,IO 是面”——做 IO 让他第一个建立全局架构理解 |
关键洞见:SRE 同理——服务端最大挑战不是写业务逻辑,而是写完后保障 7×24 运行;不碰线上就成不了最懂系统的专家。SRE 事务越多,越说明价值洼地还没被挖掘。
故障排查的方法论:假设-验证排除循环
关键判断:故障排查是可自学、可传授的技能,不是与生俱来。其本质是反复的 “假设 → 验证排除” 循环:基于观察+对系统运行机制的认知提出假设,再测试排除,直至定位根因。
高效排查需同时具备两个条件:① 对通用排查流程的理解(不依赖特定系统);② 对故障系统本身足够了解(设计方式与构建原理不可或缺)。
验证假设的两种方式:
| 方式 | 做法 | 注意 |
|---|---|---|
| 对比观察 | 把假设与观察到的系统状态对比找证据 | 较安全 |
| 主动"治疗" | 对系统做可控调整再观察结果 | 务必谨慎,避免引发更大故障 |
排查的基石:日志
关键洞见:真正意义的"线上调试"很少发生(先恢复会破坏现场),所以线上调试往往在事后进行,主要依赖日志(含监控时序数据 + 程序日志)。平常就要为排查做准备。
| 手段 | 要点 |
|---|---|
| 检查每个组件工作状态 | 监控指标是找问题的起点;看时序报表、用图表相关性初判 |
| 相关性 ≠ 因果 | 网络丢包与坏盘可能同因(断电),但彼此非因果;相关性只能找"怀疑对象" |
| 问题分解(Divide & Conquer) | 多层系统从一端逐层检查到最底层 |
| 日志(找根因关键) | 记录每步操作与系统状态;Google Dapper / 开源 OpenTracing 提供分布式追踪 |
| 多级日志 + 动态调级 | 平时少记省成本,需要时不重启进程即可调高日志级别;高流量可采样记录(如每 1000 次记一次) |
| Request ID | 给每个 API 请求分配,串起整条调用链便于检索 |
| X-RequestTrace(HTTP 头) | 更轻盈的 Tracing,实现易;但只能在线调试,无法查历史 |
| 状态查询 API / 监控页 | 暴露当前状态、RPC 采样、各类 RPC 错误率与延迟直方图;轻便,但现场被破坏后失效 |
仅靠 Request ID 看调用链不够——定位本身是"假设-验证排除"循环,所以基于时序数据的日志系统需支持多样化过滤条件(如七牛云 Pandora)。
现实的实操建议与低效根源
实操上让排查更简单的三件事:
| 建议 | 作用 |
|---|---|
| 增加可观察性 | 实现之初就给每组件加白盒指标+结构化日志(别等狼来了才补牢) |
| 用成熟、观察性好的 RPC 框架 | 用 Request ID 一致地在全系统传递,降低上下游日志对应成本 |
| 简化、控制、记录改动 | 对现存错误的假设和环境改变常引发排查,记录改动可降低排查需要 |
关键判断:建立系统化排查手段(而非靠运气经验)能限定故障恢复时间(MTTR),让新手也能快捷解决问题。
排查低效集中在"假设-验证排除"环节,根源是对系统不够了解,典型表现:
- 在错误方向浪费时间(关注/理解错了系统现象)。
- 把巧合或"由当前问题导致的次生问题"当成独立问题去解决(如 DB 压力大导致机房升温,却去解决温度)。
- 过早归因于极不可能因素,或念念不忘旧故障。
- 不正确地改了配置/输入/环境,导致验证逻辑本身有问题。
总结
故障排查 = 反复"假设-验证排除"直至定位根因;日志(广义,含时序指标+程序日志)在其中起关键作用。理解自身推理过程的错误、区分"知道什么/不知道什么/还需知道什么",是避免低效的第一步;而这一切都有赖于对业务系统运行原理与分布式基本模式的扎实理解。
先把"是什么"回答清楚
| 概念 | 一句话说明 |
|---|---|
| 先恢复后归因 | 故障第一优先是让问题消失,而非当场修好 |
| 假设-验证排除 | 故障排查的核心循环,可学习可传授 |
| 相关性≠因果 | 同时发生只是"怀疑对象",需进一步分析 |
| 问题分解 | 多层系统从一端逐层排查到底层 |
| Request ID / Tracing | 串起调用链;Dapper/OpenTracing 做分布式追踪 |
| MTTR | 平均故障恢复时间,系统化排查可限定它 |
一句话速记
故障来了先恢复再归因;排查不是天赋而是"假设-验证排除"的可传授循环,靠广义日志(时序指标+程序日志+Request ID 调用链)找根因,记住相关性不等于因果。
几条值得记住的判断
- 先恢复、后归因:回滚/扩容降级/切流量按初判选。
- 相关性 ≠ 因果,相关只能锁定怀疑对象。
- 日志要支持动态调级与采样,不重启即可加详查。
- 排查低效的根源是对系统不够了解,可观察性要在实现之初就建好。
思考题
文中说"不碰线上就无法成为最理解系统的专家"。回到你的系统:如果现在突发一次入口级故障,你能在不破坏现场的前提下,靠现有日志走完一轮"假设-验证排除"吗?如果不能,缺的是 Request ID 全链路串联、还是动态可调的日志级别?
