Spring Boot嵌入式Tomcat服务部署时停止响应请求求助
问题分析与解决方案
首先,咱们来拆解下你遇到的问题:服务明明还在监听端口,但完全不响应请求,核心原因大概率和你在服务运行时移动target目录的操作有关,具体分析和解决办法如下:
根因分析
Linux系统中,虽然进程打开的文件句柄不会因为目录移动而直接失效(因为文件的inode没变化),但你的Spring Boot应用可能存在以下依赖场景:
- 应用运行时需要读取
target目录下的其他文件(比如外部配置、静态资源、自定义的业务文件等),当target被移走后,这些文件的路径直接失效,导致请求处理线程卡在文件读取操作上,最终整个Tomcat线程池被占满,无法处理新请求。 - 嵌入式Tomcat会对部分资源路径做缓存,当
target目录结构被修改(移走再重建)后,缓存的路径失效,引发资源加载异常,阻塞请求流程。
解决方案
1. 修正部署流程(最直接的解决方式)
永远不要在服务运行时移动存放当前运行Jar包的目录,正确的部署步骤应该是:
- 停止当前服务:
先找到进程ID:
然后优雅停止(如果配置了actuator的shutdown端点,也可以用ps aux | grep abc.jar | grep -v grepcurl -X POST localhost:8090/shutdown):kill <进程ID> - 备份旧Jar包:
不要移动整个target目录,而是单独备份Jar文件:mkdir -p old_target cp target/abc.jar old_target/abc.jar.$(date +%Y%m%d%H%M%S) - 部署新Jar包:
将新Jar包复制到target目录后,重新启动服务:java -jar -Dspring.profiles.active=local -Dserver.port=8090 target/abc.jar > /dev/null 2>&1 &
2. 临时恢复当前无响应的服务
如果你想快速验证目录移动是否是根因,可以尝试把old_target移回原来的位置:
mv old_target target
如果服务恢复响应,就可以确认是目录移动导致的问题。
3. 生产环境的零停机部署方案(进阶)
如果需要避免服务中断,推荐以下方式:
- 使用容器化部署:比如用Docker打包你的Spring Boot应用,通过Docker的滚动更新功能实现零停机部署。
- 采用蓝绿部署策略:先启动新版本的服务(使用不同端口或域名),验证正常后切换流量到新版本,再停止旧版本服务。
- 借助Spring生态工具:比如Spring Cloud Gateway作为网关,配合服务注册中心(Eureka)实现平滑的服务切换。
4. 排查具体阻塞原因(定位问题细节)
如果想进一步确认是哪个环节出了问题,可以做以下操作:
- 查看应用日志:如果你的应用配置了文件日志(不是只重定向到/dev/null),去日志目录查看是否有文件读取失败、线程阻塞相关的报错。
- 导出线程栈:用
jstack命令查看线程状态:
打开jstack <进程ID> > thread_dump.txtthread_dump.txt,查找处于BLOCKED或WAITING状态的线程,看是否和文件操作相关。 - 查看文件句柄:用
lsof命令确认进程打开的文件:
可以看到原来的Jar文件是否还被进程正常持有。lsof <进程ID> | grep abc.jar
内容的提问来源于stack exchange,提问作者Shubham
相关产品推荐
相关产品推荐

