springboot2突然间假死了,请问你的排查路径是怎么样?
嗯,用户问的是Spring Boot 2应用假死的问题,这确实是个棘手的情况。用户可能是位后端开发工程师,正在线上故障排查,语气里透着焦急。ta需要的是系统化的排查步骤,而不是零散的建议。
假死意味着应用无响应但进程还在,这通常比直接崩溃更难排查。我回忆了下常见的故障模式,需要从资源、线程、外部依赖和代码四个维度切入。用户可能已经试过重启,但想找到根本原因避免复发。
首先想到的是线程阻塞,这占了假死案例的大头。线程池耗尽、死锁或外部调用卡死都可能导致。用户可能没权限直接拿生产堆栈,得教ta用命令行工具。另外资源耗尽也是常见原因,特别是内存泄漏引发的OOM前兆,这时候堆转储就特别重要。
外部依赖这块容易被忽略,比如数据库连接池爆满或Redis响应慢。用户可能只盯着自己代码,忘了下游服务。还有JVM自身问题,像GC长时间停顿,不过G1出现后这种情况少多了。
最后是应用日志这个宝藏,但用户可能没配置好异步日志或滚动策略,导致IO阻塞。需要提醒ta检查日志框架的配置是否合理。
考虑到用户正在紧张排查,我把步骤按优先级排序,先快速恢复业务的方法放前面。不过要强调临时方案和根治方案的区别,避免用户以为重启就能解决问题。还补充了些容易被忽视的细节,比如Linux fd限制和JMX远程配置,这些坑当年可没少让我熬夜。
Spring Boot 2应用假死(无响应但进程仍在)是一个棘手的问题。我会按照以下路径进行系统化排查,从最外层资源问题逐步深入到代码逻辑和依赖:
1. 快速查看基础资源(1分钟)
- CPU: top -H -p <PID> 看是否某个线程占满单核
- 内存:
- free -m 看系统剩余内存
- jstat -gcutil <PID> 1000 观察GC频率(尤其Full GC)
- 磁盘: df -h 看日志磁盘是否写满
- 网络: netstat -ant | grep ESTAB | wc -l 检查连接数是否爆满
关键动作:若发现资源耗尽(如OOM),立即用jmap -dump:live,format=b,file=heap.hprof <PID>保存堆快供后续分析。
2. 抓取线程堆栈(核心步骤)
# 1. 获取Java进程PID
jps -l
# 2. 连续3次抓取线程栈(间隔5秒)
for i in {1..3}; do jstack <PID> > jstack_$(date +%H%M%S).log; sleep 5; done
# 3. 生成火焰图(需async-profiler)
./profiler.sh -d 60 -f flamegraph.html <PID>
分析重点:
- 线程状态分布:大量BLOCKED/WAITING线程?
- 重复堆栈:查找高频出现的相同堆栈(可能死锁/资源争抢)
- 线程池状态:如Tomcat线程池是否全卡在RUNNABLE但无进展
3. 检查内部阻塞点
A. 同步锁竞争
- 检查synchronized或ReentrantLock是否未释放
- 用jstack查找waiting to lock <0x000000070ff00000>
B. 死锁检测
jstack <PID> | grep -A 10 "deadlock" # JVM会自动标记死锁
C. 外部资源阻塞
- 数据库连接池(如HikariCP):
- sql
- 复制
- 下载
- SHOW PROCESSLIST; -- 检查是否有慢查询阻塞连接
- Redis/MQ客户端:查看getTimeout配置是否合理
D. 阻塞IO操作
- 文件读写未设超时(尤其是大文件)
- 同步网络调用(如HttpClient未设超时)
4. 内存问题排查
# 实时监控GC
jstat -gcutil <PID> 1000
# 检查内存泄漏(MAT分析)
jmap -histo:live <PID> | head -20
- 现象:频繁Full GC但回收效果差,堆内存持续高位
- 常见原因:缓存未清理、静态集合持续增长、未关闭资源(如InputStream)
5. 应用日志分析
- 搜索关键字:
- TimeoutException
- Connection pool full
- OutOfMemoryError
- Deadlock
- Thread starvation(线程饥饿)
- 日志突然中断?可能是日志框架(如Logback)异步写入阻塞
6. 网络及外部依赖
- 数据库:慢查询导致连接池耗尽
- SELECT * FROM information_schema.processlist WHERE TIME > 60;
- 下游HTTP服务:是否响应超时?用curl -v --max-time 3 http://endpoint测试
- DNS解析:检查/etc/resolv.conf,避免解析超时
7. Spring Boot特定问题
- Actuator端点阻塞:如heapdump生成时暂停所有线程
- 自动配置冲突:检查@ConditionalOnClass是否引入不兼容库
- 定时任务阻塞:@Scheduled任务未结束导致后续任务积压
- @Scheduled(fixedDelay = 5000) public void task() throws InterruptedException { Thread.sleep(10000); // 下一次执行被延迟 }
8. 高级诊断工具
工具 | 用途 |
Arthas | 动态跟踪方法执行耗时、监控调用链路 |
Prometheus+Grafana | 监控JVM/应用指标历史趋势 |
perf | Linux内核级性能分析 |
# Arthas示例:监控方法调用
watch com.example.service.*Service * '{params, returnObj}' -x 3
临时恢复建议
- 安全重启:先摘除流量(如Nginx下线节点),再重启实例
- 降级策略:关闭非核心功能(如用@ConditionalOnProperty动态降级)
- 扩容:临时增加实例分担负载
根治措施
- 线程池隔离:核心业务与非核心业务使用独立线程池
- 熔断降级:集成Resilience4j或Sentinel
- 完善监控:
- JVM指标(GC时间/堆内存)
- 线程池活跃数/队列大小
- 外部调用P99耗时
- yaml
- 复制
- 下载
- # Spring Boot Actuator配置 management.endpoints.web.exposure.include: health,metrics,threaddump
通过以上路径,90%的假死问题可被定位。关键是先抓现场(线程栈+内存快照)再分析,避免重启后证据丢失。