接手过不少"查不出原因"的故障,最后绝大多数都指向同一个结论:不是问题本身多诡异,而是排查顺序乱了。这次我想用一次后台订单服务故障的真实排查经历,完整拆解"故障排查及修复"应该怎么干——从接到告警、固定现场、定位根因、修复验证,到最后的复盘加固,每一环都讲讲我当时是怎么判断、为什么这么选、中间踩过哪些坑。内容偏后端服务方向,但排查思路和工具方法论是通用的,做运维、做开发、甚至自己维护小服务的同学都能直接拿来用。
1. 故障刚发生的那一步:先固定现场,而不是急着改配置
1.1 接到告警后我在前十分钟做了什么
晚上八点出头,告警群里开始刷消息:订单服务的错误率指标突然从平时的 0.2% 蹿到了 6%,P99 延迟从 300ms 涨到 4 秒,紧接着网关那边也报 502 比例升高。群里有同事第一反应是"重启一下服务试试",我拦住了。
这里有个非常关键的原则:故障现场是线上环境里最珍贵的证据,重启会把现场彻底毁掉。尤其是偶发性故障,一旦重启,线程栈、连接状态、内存里的异常对象全部消失,后面就只能靠猜。我在前十分钟只做了三件事:
- 在告警群里固定时间线:故障从什么时候开始、持续多久、由哪个监控指标触发。
- 确认影响范围:是全部接口都挂了,还是只有下单接口慢?是所有用户都失败,还是某些特定请求失败?
- 拉取最近变更记录:过去两小时有没有发布、配置修改、数据库 DDL、流量切换。
这三件事看起来简单,但很多人遇到故障就直接扎进日志里翻,反而漏掉了最重要的背景信息。我当时查了发布平台,确认下午六点刚发过一个版本,改动内容里有一条 SQL 优化。这个信息在后面起了决定性作用——它给了我们一个重点怀疑方向,而不是漫无目的地全链路排查。
1.2 把"偶发性故障"从玄学变成可量化指标
故障里最让人头疼的就是"偶发"两个字。用户反馈时好时坏,你盯着屏幕的时候它偏偏正常。处理这类问题的办法只有一个:给"偶发"建立坐标系。
我的做法是同时拉三组数据做时间对齐:
- 网关层 Nginx 访问日志:统计每分钟请求量、5xx 比例、响应时间分布。
- 应用层日志:重点找异常堆栈、慢请求日志、数据库连接获取超时记录。
- 基础设施监控:CPU、内存、GC 停顿、数据库活跃连接数、连接池指标。
把三组数据按分钟对齐后,规律一下子就出来了:错误率高峰出现在每个整点的前五分钟(比如 20:00-20:05、21:00-21:05),其他时间段虽然也有波动,但远没有达到告警阈值。这个"周期性"特征非常关键,它直接排除了网络抖动、机房故障这类随机性原因,把怀疑范围收敛到了"某个定时任务"或"某个周期性的业务高峰"上。
我这几年排查故障最深的一个体会是:大部分所谓疑难杂症,都是因为证据不够。证据够了,根因自己会跳出来。 所以遇到问题先别急,把时间线、指标、日志摆齐了再动手。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 排查链路拆解:从日志里找证据,而不是凭感觉怀疑
2.1 应用日志中的三个关键信息抽取点
固定完现场,我开始系统性地翻日志。翻日志不是全文搜"Exception"就完事,要有目的地找三类信息:
- 异常类型与频次:是
ConnectionTimeoutException还是Connection is not available, request timed out?后者说明连接池已经耗尽,前者可能是网络问题。同一时间段内同类异常的出现次数,直接反映问题的严重程度。 - 异常出现的位置:堆栈里是发生在 MyBatis 执行 SQL 的时候,还是在调用远程服务的时候?这决定了问题出在数据库端还是下游服务端。
- 请求关联 ID:通过 Trace ID 把同一个请求在网关、应用、数据库三条链路上的时间串起来,看时间到底消耗在哪一段。
我当时在日志里翻到了一个反复出现的报错:`HikariPool-1 - Connection is not a
