Apache Fusion服务器Jetty线程线性增长致OOM,求线程限制方案
解决Jetty线程线性增长导致OOM的问题
让我来帮你梳理下可能的原因和解决办法——我之前也碰到过类似的Jetty线程泄漏问题,相同配置不同服务器表现差异大,大概率是特定场景下的线程泄漏,而非单纯的配置不生效。
第一步:先确认你的线程池配置真的在生效
有时候start.ini的参数会被其他配置文件覆盖,别想当然认为设置了就生效:
- 利用你已经启用的
jmx模块,用jconsole或者jvisualvm连接服务器,找到org.eclipse.jetty.util.thread.ThreadPool这个MBean,查看实际的minThreads、maxThreads和idleTimeout是不是和你start.ini里的一致。 - 检查有没有其他XML配置文件(比如
etc/jetty.xml或者自定义的配置)里定义了QueuedThreadPool,如果有,这些XML的配置优先级可能比start.ini更高,会覆盖你的参数。
第二步:排查线程泄漏的核心原因
线程线性增长到上限,基本都是线程泄漏——正常情况下Jetty的线程池会复用线程,空闲超时后会销毁到minThreads数量。你需要找出哪些线程在不断创建却没被回收:
- 用
jstack <PID>导出线程栈,或者直接用New Relic的线程快照功能,查看大量增长的线程的栈信息:- 看看是不是有大量线程卡在阻塞状态:比如等待数据库连接池、外部API响应,或者某个锁没有释放?这种情况会导致线程一直被占用,池子里不得不创建新线程。
- 检查有没有
ThreadLocal未清理:如果业务代码里用了ThreadLocal但在请求结束后没移除,会导致线程被持有无法回收,时间长了就会堆积。 - 确认异步请求处理逻辑:如果你用了
AsyncContext(比如Servlet 3.0异步),有没有在处理完成后调用complete()?如果没调用,Jetty会一直持有这个线程不放。
- 对比正常服务器和出问题服务器的流量、请求类型:是不是有特定的接口或者请求触发了线程泄漏?比如某个新上线的接口、大流量的请求类型。
第三步:确保线程池配置正确生效(如果确认配置被覆盖)
如果发现start.ini的参数没生效,可以直接在etc/jetty.xml里硬编码线程池配置,优先级更高:
<Set name="threadPool"> <New class="org.eclipse.jetty.util.thread.QueuedThreadPool"> <Set name="minThreads">10</Set> <Set name="maxThreads">150</Set> <Set name="idleTimeout">5000</Set> <Set name="detailedDump">true</Set> <!-- 开启详细线程dump,方便调试 --> </New> </Set>
另外,检查你启用的模块有没有影响线程池:比如continuation模块是用来支持异步处理的,如果异步逻辑有问题,也会导致线程无法释放。
第四步:开启更详细的调试辅助
- 在start.ini里添加
jetty.threadPool.detailedDump=true,这样当你dump线程的时候,能看到每个线程处理的请求路径、状态,更容易定位泄漏点。 - 利用New Relic的线程分析功能,查看线程的创建来源,有没有重复创建的自定义线程组,或者异常的线程生命周期。
第五步:排查第三方组件的问题
有时候线程泄漏不是Jetty本身的问题,而是依赖的第三方库导致的:
- 检查有没有使用的客户端(比如Apache HTTP Client、Redis客户端)创建了自己的线程池,却没有正确关闭?比如有些客户端默认会创建后台线程,如果你每次请求都新建客户端实例,就会导致线程堆积。
- 对比正常服务器和出问题服务器的依赖版本:是不是某个组件版本不一致,引入了线程泄漏的bug?
内容的提问来源于stack exchange,提问作者Nishkarsh Dixit
相关产品推荐
相关产品推荐

