15

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

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)
4

3 に答える 3

7

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

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

この問題は、GWT RPC 呼び出しの一部としての要求中にタイムアウトになった QTP スレッドのセマフォ ロックに関係しています。元のリクエストは時間制限があり、タイムアウトは 30 秒です。Semaphore.acquire メソッドが完了するのを待っている間に、要求がタイムアウトします。リクエストのクリーンアップの一環として、HTTPConnection はリクエストで .consumeAll を試行し、これが再び Sempahore.acquire を試行します。今回は、リクエストは時間制限されず、スレッドが中断されるまでロックが維持されます。

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

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

于 2013-10-01T11:56:50.003 に答える