SpringNotes

第 26 章:故障排查

zjc 于 2026-01-26 发布

这是《Spring Boot 与 Spring Cloud 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 故障排查的目标是快速恢复,其次才是找根因。先止血、保留证据、再修复和复盘。微服务故障往往跨多层,需要同时看入口、服务、依赖和平台。

26.1 应急流程

1. 发现和确认影响
2. 通知相关团队
3. 保留现场证据
4. 尝试止血
5. 验证恢复
6. 根因分析
7. 修复和发布
8. 复盘和预防

止血方式:

  1. 回滚版本;
  2. 扩容;
  3. 降级非核心功能;
  4. 切换流量;
  5. 重启实例;
  6. 限流;
  7. 修复配置;
  8. 数据库紧急处理。

26.2 分层排查

入口
  -> DNS / LB / Gateway
     -> Service
        -> Controller
        -> Service Layer
        -> DB / Cache / MQ / Downstream
     -> Platform
        -> Pod / Node / Network

先确认影响范围:

范围 方向
单实例 节点或实例问题
某服务所有实例 代码、配置、依赖
某机房 网络、依赖、云资源
全站 网关、DNS、核心依赖
某用户 权限、数据、缓存
某接口 SQL、下游、业务逻辑

26.3 接口 5xx

排查:

1. 网关访问日志
2. 服务错误日志
3. traceId 链路
4. 异常类型和堆栈
5. 发布和配置变更
6. 依赖健康状态

常见原因:

异常 方向
NullPointerException 代码和数据边界
SQLSyntaxErrorException 发布脚本或实体映射
ConnectTimeoutException 下游不可用
Pool exhaustion 慢 SQL 或下游慢
ClassNotFoundException 依赖或打包问题
IllegalStateException 状态机和初始化顺序

26.4 接口慢

查看分段耗时:

总耗时
网关耗时
服务内部耗时
SQL 耗时
RPC 耗时
Redis 耗时
锁等待
线程池排队

常见瓶颈:

  1. N+1 查询;
  2. 缺索引;
  3. 下游超时;
  4. 缓存失效;
  5. 大 JSON;
  6. synchronized 竞争;
  7. GC 停顿;
  8. CPU throttling。

26.5 服务不可用

应用检查:

curl http://host:8080/actuator/health
ps -ef | grep java
jcmd <pid> Thread.print
ss -lntp | grep 8080

容器检查:

kubectl get pod -o wide
kubectl describe pod <pod>
kubectl logs <pod> --previous
kubectl exec -it <pod> -- sh

常见问题:

现象 原因
OOMKilled 容器内存
CrashLoopBackOff 启动异常
ImagePullBackOff 镜像或凭证
Pending 资源或调度
readiness fail 健康检查
restart count 高 异常退出

26.6 线程池耗尽

现象:

  1. 请求排队;
  2. rejected 增长;
  3. CPU 低;
  4. 大量线程 BLOCKED 或等待 IO。

排查:

jcmd <pid> Thread.print > thread.txt

方向:

  1. 下游超时缺失;
  2. 数据库连接不足;
  3. 锁竞争;
  4. 任务执行慢;
  5. 队列无界;
  6. 流量突增。

处理:

  1. 限流;
  2. 降级;
  3. 设置超时;
  4. 隔离线程池;
  5. 修复慢依赖;
  6. 再评估容量。

26.7 数据库故障

现象:

  1. 连接池 pending;
  2. SQL 超时;
  3. 锁等待;
  4. 主从延迟;
  5. 磁盘 IO 高。

排查:

show processlist;
show engine innodb status;
select * from information_schema.innodb_trx;

处理:

  1. kill 明确异常的长时间事务;
  2. 回滚问题 SQL;
  3. 限流写入;
  4. 切换读库;
  5. 联系 DBA;
  6. 事后补索引和优化。

26.8 消息积压

排查:

  1. consumer lag;
  2. 消费耗时;
  3. 重试和死信;
  4. 分区分布;
  5. 消费实例数;
  6. 下游状态。

处理:

  1. 扩容消费者,不能超过有效并发能力;
  2. 临时降级非关键逻辑;
  3. 修复慢消费;
  4. 跳过无效死信,必须记录;
  5. 提高下游吞吐;
  6. 观察消费幂等。

26.9 保留证据

必须保存:

时间线
告警截图
监控快照
trace 链接
GC 日志
线程 dump
堆 dump
应用日志
网关日志
平台事件
变更记录
聊天记录

重启前优先保留:

jcmd <pid> Thread.print > thread.txt
jcmd <pid> GC.heap_dump heap.hprof
jcmd <pid> VM.flags > flags.txt

注意 heap dump 会 STW,要评估影响。

26.10 故障复盘

模板:

故障编号
时间
影响
时间线
根因
触发条件
为什么没有提前发现
为什么没有自动恢复
应急过程
改进项
负责人和截止时间

改进动作要具体、可测量、有负责人和截止时间。

本章小结

故障排查要先确认影响范围,再按入口、服务、依赖和平台分层定位。常见故障集中在 5xx、慢请求、线程池耗尽、数据库、消息积压和容器资源。应急时先止血并保留证据,恢复后通过复盘把发现和恢复能力产品化。

思考题

  1. 为什么先止血再根因分析?
  2. 如何确认故障影响范围?
  3. CPU 低但请求排队说明什么?
  4. 消息积压时如何安全扩容?
  5. 故障复盘最重要的输出是什么?