web-dev-qa-db-ja.com

Jetty 9がハングし、QueuedThreadPoolが大きくなります

最近、Jettyサーバーをバージョン6.1.25から9.0.4にアップグレードしました。これらは、Windows2008サーバー上のJava 1.7.0_1164ビットにデプロイされます。

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に関連している可能性があると考えられましたが、それ自体は記事のようには表示されておらず、このケースはJetty9.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関連(それを行った)のいずれかでプログラム的であると信じています。また、私がスレッドで赤ニシンを追いかけているのではないかと思われる場合は、提案を受け付けています。

新しい情報:例外をもう少し追跡すると、これはGWTRPC呼び出しが応答を待っている間にタイムアウトしたときに発生したようです。次のスタックトレースは、無効な状態にあるスレッドに関連するログファイルの例外を示しています。これを使用して、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)
13
skimbleton

結局、Eclipse/JettyのWebサイトに質問を投稿することになりました。次のリンクを使用して、ソリューションに対する永続的な修正を追跡できます。

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

この問題は、GWTRPC呼び出しの一部としてリクエスト中にタイムアウトになったQTPスレッドのセマフォロックに関係しています。元のリクエストは、30秒のタイムアウトでタイミングが取られます。 Semaphore.acquireメソッドの完了を待機している間、リクエストはタイムアウトします。リクエストのクリーンアップの一環として、HTTPConnectionはリクエストで.consumeAllを試行し、Sempahore.acquireを再度試行します。今回は、リクエストのタイミングは設定されず、スレッドが中断されるまでロックは保持されます。

Jettyは問題を再現できず、他の問題のレポートも見つからないため、この問題はプラットフォームに非常に固有であるように見えます。さらに、これは1つの実稼働環境でのみ発生します。私の推測では、GWT RPCコード、Jetty、およびオペレーティングシステムの間で何かが起こっていると思います。 JDK、Jetty、GWTSDKのマイナーアップグレードが計画されています。

回避策最初の回避策は、JMXコンソールを介してロックされたスレッドを1日に数回手動で中断することでした。私たちの長期的な解決策は、これらのロックされたスレッドを探し、それらの割り込みメソッドを呼び出すクリーンアップメカニズムを構築することでした。

7
skimbleton

QueuedThreadPoolは、スレッドの共有プールです。その中のスレッドは他の処理に再利用されます。はい、スレッドがクリーンアップされると仮定して、スレッドプールを追跡することは、赤いニシンです。これらのスレッドは、長期間(数時間考えてください)にわたってゆっくりとプールから落ちます。これはスレッドプールでのパフォーマンスの決定です(作成にはコストがかかります。できるだけ頻繁に実行しないでください)。

貼り付けたスタックトレースは不完全なので、動作の推測量が非常に多くなります。とはいえ、これらの2行canは通常の操作を示していますが、残りのスタックトレースがないと、先に進むことはほとんどありません。

また、1.7.0_06と1.7.0_11を使用しているJavaのバージョンは非常に古く、何百ものバグ修正が行われています。

1
Joakim Erdfelt

Jetty9.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
1
sytolk