springboot2突然间假死了,请问你的排查路径是怎么样?

springboot2突然间假死了,请问你的排查路径是怎么样?

经验文章nimo972025-06-30 21:48:362A+A-


嗯,用户问的是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. 同步锁竞争

  • 检查synchronizedReentrantLock是否未释放
  • 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

临时恢复建议

  1. 安全重启:先摘除流量(如Nginx下线节点),再重启实例
  2. 降级策略:关闭非核心功能(如用@ConditionalOnProperty动态降级)
  3. 扩容:临时增加实例分担负载

根治措施

  • 线程池隔离:核心业务与非核心业务使用独立线程池
  • 熔断降级:集成Resilience4j或Sentinel
  • 完善监控
    • JVM指标(GC时间/堆内存)
    • 线程池活跃数/队列大小
    • 外部调用P99耗时
  • yaml
  • 复制
  • 下载
  • # Spring Boot Actuator配置 management.endpoints.web.exposure.include: health,metrics,threaddump

通过以上路径,90%的假死问题可被定位。关键是先抓现场(线程栈+内存快照)再分析,避免重启后证据丢失。

点击这里复制本文地址 以上内容由nimo97整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

尼墨宝库 © All Rights Reserved.  蜀ICP备2024111239号-7