线上故障不靠猜:一套可复用的系统化排查方法
从界定影响、沿链路验证到恢复与复盘,整理一套适合个人项目和小团队复用的线上故障处理方法。
线上故障最让人紧张的时刻,往往不是错误出现,而是所有人同时开始猜测:是不是数据库慢了?是不是刚才发布的版本有问题?要不要先重启?在缺少证据时,每一个“快速尝试”都可能覆盖现场,让原本可定位的问题变得更复杂。 一次高质量的故障处理,不要求维护者立即知道答案,而要求他能稳定地缩小范围、控制影响、保留证据,并在恢复后把经验变成系统能力。下面以个人博客接口大量返回 502 为例,整理一套可复用的排查方法。 ## 一、先确认影响,不要先寻找原因 故障发生后先回答四个问题: 1. 哪些用户受影响,是所有访客还是仅后台用户? 2. 哪些路径失败,是首页、文章接口还是全部 API? 3. 从什么时候开始,是否与发布或配置变更重合? 4. 失败是持续发生还是间歇出现? 这一步的目标是建立边界。例如静态首页正常、所有 `/api` 返回 502,说明浏览器到 Nginx 的链路大概率正常,问题更可能位于反向代理到后端之间。若只有图片失败,则应优先检查上传目录、权限和路径,而不是数据库。 把时间、症状和影响范围写下来。即使只有一个人处理,也建议维护一条简短时间线,因为紧张状态下人的记忆并不可靠。 ## 二、按请求链路逐层验证 不要跳着检查。沿着用户请求经过的顺序,从外向内验证: ```text DNS → TLS → Nginx → 后端端口 → 应用健康 → 数据库 → 业务数据 ``` 每一层只问一个问题:“这一层能否完成它应该完成的最小动作?” DNS 层检查域名是否指向正确地址;TLS 层确认握手和证书;Nginx 层查看配置是否加载、静态文件能否返回;后端层直接请求本机健康接口;数据库层执行一个只读查询;业务层再请求具体文章。 这种顺序看起来比直接重启慢,实际往往更快,因为每一步都排除一大片可能性。 ## 三、区分进程存在和服务可用 `systemctl status` 显示进程正在运行,不代表应用可以正常处理请求。Java 进程可能卡在数据库连接、内存压力或迁移失败后的异常状态中。 健康检查至少分两层: - **存活检查**:进程是否还能响应; - **就绪检查**:数据库等关键依赖是否可用,应用是否适合接收请求。 如果健康接口失败,查看服务最近日志;如果健康接口正常但公网失败,重点检查 Nginx upstream、监听地址和防火墙。后端只监听 `127.0.0.1` 是合理的安全设置,但 Nginx 必须与它处于同一网络环境。 ## 四、日志要围绕时间线阅读 日志很多时,不要从文件开头漫无目的地滚动。以故障开始时间为中心,先看前后几分钟,再按错误类型聚合。 重点关注: - 应用是否刚刚重启; - 数据库连接是否超时或耗尽; - Flyway 是否报告迁移失败; - 是否出现内存不足或线程池拒绝; - Nginx upstream 是连接被拒绝、连接超时还是读取超时; - 同一请求是否有可以串联前后端的标识。 “connection refused”通常意味着目标端口没有监听,“read timed out”则意味着连接建立后迟迟没有结果。两者都表现为 502 或 504,但排查方向完全不同。 ## 五、评估最近变更,但不要默认它一定有错 最近一次发布是重要线索,却不是唯一原因。证书过期、磁盘写满、数据库重启和外部邮件服务异常,也可能恰好发生在发布附近。 检查变更时可以采用对照法:新旧版本的应用包、环境变量、数据库迁移和 Nginx 配置分别发生了什么变化?如果可以安全回滚应用版本,而数据库结构仍向后兼容,那么回滚能快速验证是否与代码有关。 如果迁移包含删除列、重命名或不可逆数据转换,回滚旧应用可能造成更严重问题。因此发布前必须明确迁移的兼容窗口,而不是故障时临时判断。 ## 六、恢复优先于完美定位 当影响持续扩大时,应先恢复服务,再完成深入分析。可选动作按风险从低到高排序: 1. 暂停新的发布与写入; 2. 切回已验证的上一应用版本; 3. 临时关闭非核心能力,例如邮件通知; 4. 扩容或释放明确耗尽的资源; 5. 从已验证备份恢复数据。 重启并非禁用动作,但要先保存日志、线程或内存信息。如果每次重启都让问题暂时消失,却不保留证据,故障很可能周期性返回。 所有高风险命令都应该明确目标,避免对宽泛目录使用递归删除,也不要在变量未展开时执行破坏性操作。事故处理中,第二次事故经常来自仓促的修复命令。 ## 七、验证恢复要覆盖真实用户路径 进程恢复后不要立刻宣布结束。至少验证: - 公开首页和文章详情能够访问; - API 返回结构与状态码正确; - 管理员可以登录并读取后台; - 数据库可以读写; - 图片可以加载; - 新评论或草稿可以正常保存; - 错误率和延迟回到正常范围。 如果采取了临时措施,要记录哪些功能仍被关闭、何时恢复。故障状态从“中断”变为“降级”时,对外沟通也应同步更新。 ## 八、复盘关注系统,不归咎个人 有效复盘至少包含五部分: ```text 影响:用户实际经历了什么 时间线:发现、响应、恢复分别在何时 根因:什么条件共同触发了问题 促进因素:为什么问题扩大或难以及时发现 行动项:如何降低再次发生的概率和影响 ``` “某个人操作失误”通常不是足够的根因。为什么一个操作可以未经检查进入生产?为什么没有回滚?为什么告警没有提前发现?把问题继续向系统层追问,才能得到可执行的改进。 行动项要有优先级和可验证结果。“加强监控”太模糊;“增加公网首页与后端健康接口的五分钟状态转换告警”更容易执行和验收。 ## 九、把经验写进工具 复盘的价值不在文档数量,而在下一次响应是否更快。可以把经验转化为: - 自动化部署前检查; - 可重复的数据库迁移联调; - 原子发布与自动回滚; - 健康检查和状态转换告警; - 备份校验与恢复演练; - 一页式故障处理清单。 当同一问题第二次发生时,系统应该比第一次更容易给出证据。维护能力就是这样逐步积累起来的。 ## 结语 系统化排查的核心不是掌握更多神奇命令,而是保持顺序:先界定影响,再沿链路验证;先保留证据,再采取动作;先恢复核心服务,再追求完整解释;最后把经验变成自动化能力。 故障不可完全避免,但混乱可以减少。一个人维护的小站同样值得拥有清晰的响应方式,因为越是在资源有限的环境里,可靠的方法越能节省时间。