Jetty 9挂起,队列线程池变大

Jetty 9挂起,队列线程池变大,jetty,Jetty,我们最近将Jetty服务器从版本6.1.25升级到9.0.4。它们部署在Windows 2008服务器上的Java 1.7.0_11 64位上 除了Jetty所需的配置更改(start.ini-非常好),我们将所有JVM标志保持与以前相同。在生产环境中部署6天后,服务器对HTTP请求没有响应。在此期间,内部“心跳”处理继续按正常方式运行,但它不服务于外部请求。该服务被重新启动,6天后再次失去响应 在我最初的复习中,我认为我已经掌握了一些知识。然而,JVM问题是从Java1.8_0XX向后移植到J

我们最近将Jetty服务器从版本6.1.25升级到9.0.4。它们部署在Windows 2008服务器上的Java 1.7.0_11 64位上

除了Jetty所需的配置更改(start.ini-非常好),我们将所有JVM标志保持与以前相同。在生产环境中部署6天后,服务器对HTTP请求没有响应。在此期间,内部“心跳”处理继续按正常方式运行,但它不服务于外部请求。该服务被重新启动,6天后再次失去响应

在我最初的复习中,我认为我已经掌握了一些知识。然而,JVM问题是从Java1.8_0XX向后移植到Java1.7.0_06的。这让我回顾了线程处理

我认为它可能与eclipse站点上的案例400617/410550有关,尽管它本身并不完全像这篇报道,而且该案例显然已在Jetty 9.0.3中得到解决

通过JMX监控应用程序表明,随着时间的推移,“qtp”线程的线程数继续增加,我在搜索解决方案时失败了。线程配置当前设置为:

threads.min=10
threads.max=200
threads.timeout=60000
所有qtp线程通常处于等待状态,堆栈跟踪如下:

Name: qtp1805176801-285
State: WAITING on java.util.concurrent.Semaphore$NonfairSync@4bf4a3b0
Total blocked: 0  Total waited: 110

Stack trace: 
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.park(Unknown Source)
java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(Unknown Source)
java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(Unknown Source)
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(Unknown Source)
java.util.concurrent.Semaphore.acquire(Unknown Source)
org.eclipse.jetty.util.BlockingCallback.block(BlockingCallback.java:96)
org.eclipse.jetty.server.HttpConnection$Input.blockForContent(HttpConnection.java:457)
org.eclipse.jetty.server.HttpInput.consumeAll(HttpInput.java:282)
   - locked org.eclipse.jetty.util.ArrayQueue@3273ba91
org.eclipse.jetty.server.HttpConnection.completed(HttpConnection.java:360)
org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:340)
org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:224)
org.eclipse.jetty.io.AbstractConnection$ReadCallback.run(AbstractConnection.java:358)
org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:601)
org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:532)
java.lang.Thread.run(Unknown Source)
仔细观察后,这与具有以下状态的最新线程不同:

Name: qtp1805176801-734
State: TIMED_WAITING on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@77b83b6e
Total blocked: 5  Total waited: 478

Stack trace: 
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Unknown Source)
org.eclipse.jetty.util.BlockingArrayQueue.poll(BlockingArrayQueue.java:390)
org.eclipse.jetty.util.thread.QueuedThreadPool.idleJobPoll(QueuedThreadPool.java:509)
org.eclipse.jetty.util.thread.QueuedThreadPool.access$700(QueuedThreadPool.java:48)
org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:563)
java.lang.Thread.run(Unknown Source)
根据命名约定,一些qtp线程非常旧(qtp1805176801-206),而一些非常新(qtp1805176801-6973)。我发现有趣的是,旧线程没有基于60秒空闲超时超时超时。该应用程序在美国营业时间为客户提供服务,在清晨的几个小时里基本上处于空闲状态,我希望在这个时候几乎所有的池都会被清理干净

希望有人能为我指出正确的方向,如何追踪这个问题。我在Jetty的经验使我相信他们的东西非常可靠,大多数问题要么是在我们的实现中编程的(已经存在),要么是与JVM相关的(已经完成)。如果你认为我可能是在转移注意力,也可以接受建议

新信息: 进一步跟踪异常,这似乎是由于GWT RPC调用在等待响应时超时造成的。以下堆栈跟踪显示日志文件中与处于无效状态的线程相关的异常。使用此功能查看和查找Jetty/GWT交互问题的其他报告

2013-09-03 08:41:49.249:WARN:/webapp:qtp488328684-414: Exception while dispatching incoming RPC call
java.io.IOException: java.util.concurrent.TimeoutException: Idle timeout expired: 30015/30000 ms
    at org.eclipse.jetty.util.BlockingCallback.block(BlockingCallback.java:103)
    at org.eclipse.jetty.server.HttpConnection$Input.blockForContent(HttpConnection.java:457)
    at org.eclipse.jetty.server.HttpInput.read(HttpInput.java:130)
    at java.io.InputStream.read(Unknown Source)
    at com.google.gwt.user.server.rpc.RPCServletUtils.readContent(RPCServletUtils.java:175)
    at com.google.gwt.user.server.rpc.RPCServletUtils.readContentAsGwtRpc(RPCServletUtils.java:205)
    at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.readContent(AbstractRemoteServiceServlet.java:182)
    at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:239)
    at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:755)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:698)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1506)
    at c.t.b.servlet.PipelineFilter.doFilter(PipelineFilter.java:56)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1494)
    at c.v.servlet.SetRequestEncoding.doFilter(SetRequestEncoding.java:27)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1494)
    at c.t.b.servlet.OutOfMemoryFilter.doFilter(OutOfMemoryFilter.java:39)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1486)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:503)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:138)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:564)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:213)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1094)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:432)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:175)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1028)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:136)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:258)
    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:109)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
    at org.eclipse.jetty.server.Server.handle(Server.java:445)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:267)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:224)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.run(AbstractConnection.java:358)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:601)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:532)
    at java.lang.Thread.run(Unknown Source)
Caused by: 
java.util.concurrent.TimeoutException: Idle timeout expired: 30015/30000 ms
    at org.eclipse.jetty.io.IdleTimeout.checkIdleTimeout(IdleTimeout.java:153)
    at org.eclipse.jetty.io.IdleTimeout$1.run(IdleTimeout.java:50)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

QueuedThreadPool是线程的共享池。其中的线程将被重新用于其他处理。是的,追逐线程池(假设线程将被清理)是一种危险的做法。这些线程将在很长一段时间内(想想几个小时)缓慢地从池中脱落。这是线程池中的性能决定(创建是昂贵的,尽可能不频繁地创建)

至于您粘贴的stacktrace,它是不完整的,因此对行为的猜测非常多。但是也就是说,这两行可以表示正常的操作,但是如果没有stacktrace的其余部分,就没有什么可以继续的了


此外,您正在使用的Java 1.7.0_06和1.7.0_11的版本非常旧,并且您需要修复数百个错误。

最后在Eclipse/Jetty网站上发布了这个问题。以下链接可用于跟踪解决方案的任何永久性修复

该问题与QTP线程上的信号量锁定有关,QTP线程在请求期间作为GWT RPC调用的一部分超时。对原始请求进行计时,超时时间为30秒。请求在等待Semaphore.acquire方法完成时超时。作为请求清理的一部分,HTTPConnection尝试对请求执行.consumeAll,这将再次尝试执行Sempahore.acquire。这一次,请求没有计时,并且在线程中断之前,锁保持在原位

由于Jetty无法重现该问题,而且我也无法找到任何其他关于该问题的报告,因此该问题似乎对平台非常具体。此外,这只发生在我们的一个生产环境中。我的猜测是GWT RPC代码、Jetty和操作系统之间发生了一些事情。我们计划对JDK、Jetty和GWT SDK进行一些小的升级

解决方法
最初的解决方法是每天通过JMX控制台手动中断锁定线程几次。我们的长期解决方案是建立一个清理机制,查找这些锁定线程并对其调用中断方法

Jetty 9.2.3.v20140905和Java(build 1.8.0_20-b26)64位版本也有相同的功能

解决方法。安装monit


Joakim-我已经更新了堆栈跟踪以显示完整的堆栈跟踪。当我更仔细地观察时,最新的线程通常处于以下状态:我们计划在几周内将JDK版本升级到1.7.0_25(最新的Java 7稳定版本),尽管对发行说明的审查并没有表明有什么重大变化。我在Jetty 9.2上看到了这个问题(请参阅:)。jVisualVM显示运行38小时后HttpConnector螺纹开始泄漏。大约有10个线程保持活动状态,下一个连接将启动另一个线程集群以进行下一次HTTP读取。
# monit.conf
check process jetty-service with pidfile "/opt/jetty-service/jetty.pid"
start program = "/usr/sbin/service jetty-service start" with timeout 30 seconds
stop program = "/usr/sbin/service jetty-service stop"
if totalmem is greater than 1268 MB for 10 cycles then restart
if 5 restarts within 5 cycles then timeout