Jetty 9挂起,QueuedThreadPool不断增长

时间:2013-08-29 21:22:30

标签: jetty

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

除了Jetty所需的配置更改(start.ini - 非常好)之外,我们保持所有JVM标志与之前相同。在生产环境中部署6天后,服务器无法响应HTTP请求。内部心跳'在此期间,处理继续按正常运行,但它没有为外部请求提供服务。该服务重新启动,6天后又再次没有响应。

在我初次审核期间,我以为自己正在使用https://bugs.eclipse.org/bugs/show_bug.cgi?id=357318。但是,该JVM问题已从Java 1.8_0XX反向移植到Java 1.7.0_06。这让我回顾了线程处理。

认为它可能与eclipse网站上的案例400617/410550有关,虽然它不像报道那样呈现自己,并且案例在Jetty 9.0.3中显然得到了解决。

通过JMX监控应用程序显示' qtp'随着时间的推移,线程不断增长,我在寻找解决方案方面都没有成功。线程配置当前设置为:

threads.min=10
threads.max=200
threads.timeout=60000

所有qtp线程通常处于WAITING状态,并带有以下堆栈跟踪:

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)

3 个答案:

答案 0 :(得分:7)

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

https://bugs.eclipse.org/bugs/show_bug.cgi?id=416477

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

该问题确实对该平台非常具体,因为Jetty无法重现该问题,而且我无法找到任何其他问题的报告。此外,这仅发生在我们的一个生产环境中。我的猜测是GWT RPC Code,Jetty和操作系统之间发生了一些争执。我们计划为JDK,Jetty和GWT SDK进行小规模升级。

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

答案 1 :(得分:1)

QueuedThreadPool是一个共享的线程池。其中的线程将被重用于其他处理。是的,追逐线程池,假设线程将被清理,是一个红色的鲱鱼。这些线程会在很长一段时间内慢慢地从池中掉落(想想几个小时)。这是线程池中的性能决策(创建很昂贵,尽可能不频繁地执行)。

至于你粘贴的堆栈跟踪,它是不完整的,因此对行为的猜测量非常高。但话虽如此,那两行可以表示正常运行,但没有堆栈跟踪的其余部分就没什么可继续的了。

此外,您使用1.7.0_06和1.7.0_11的Java版本已经很老了,并且您需要修复数百个错误。

答案 2 :(得分:1)

我对Jetty 9.2.3.v20140905和Java(build 1.8.0_20-b26)64位也一样。

解决方法即可。安装monit http://mmonit.com/monit/

# 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