MINAを使用するJavaアプリケーションがいくつかあり、それらはすべて20のMINAスレッドを使用します。1つのアプリケーションは約10,000の同時接続を処理し、通常はアイドル状態ですが、入力を受け取ることがあります。そのアプリケーションについては、正確にプロファイルしていませんが(この質問が出ています)、別のアプリケーションは一度に約15の接続しか提供しませんが、IO作業を開始するため、非常にビジーです。 、とにかく20のMINAスレッドがありますが、これは明らかに多すぎます。
私にとって奇妙なのは、両方のアプリケーションが常にCPU時間の約30%、時には60%を、VisualVMでプロファイルされたMINAのselect()メソッドに費やしていることです。コールスタックは次のようになります。
Java.lang.Thread.State: RUNNABLE
at Sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at Sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.Java:228)
at Sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.Java:81)
at Sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.Java:87)
- locked <40ca5d54> (a Sun.nio.ch.Util$2)
- locked <24649fe8> (a Java.util.Collections$UnmodifiableSet)
- locked <3fae9662> (a Sun.nio.ch.EPollSelectorImpl)
at Sun.nio.ch.SelectorImpl.select(SelectorImpl.Java:98)
at org.Apache.mina.transport.socket.nio.NioProcessor.select(NioProcessor.Java:72)
at org.Apache.mina.core.polling.AbstractPollingIoProcessor$Processor.run(AbstractPollingIoProcessor.Java:1093)
at org.Apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.Java:64)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1110)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:603)
at Java.lang.Thread.run(Thread.Java:722)
それは忙しい世論調査に基づいているようです、それは私には本当に間違っているように聞こえます。
こんなに多いのを見て心配する必要がありますか?これは何が原因ですか?それは私が最適化する必要があるものですか、それとも睡眠やアイドルルーチンに似ていますか?スリープルーチンのようなものである場合、他のCPU作業よりも優先度が低くなるようにスケジュールされていますか?
更新: このスレッド 同じ問題のようです。私はそのアドバイスに従い、現在Java 1.7.0_45を実行していますが、10k接続のアプリケーションでselect
がCPU時間の90%を占めているのをまだ見ています。
MINA 2.0.4を使用しています。つまり、 この関連するバグ が修正されています。
残念ながら、これは数字の誤った解釈です。
私は何度もこの状況に直面しました(そして stackoverflow にも質問します)。
主な理由は、VisualVMが正しいCPU時間を表示しないことです。 RUNNING
状態のスレッド時間のパーセンテージを示しています。しかし、_Thread.State
_のドキュメントから:
実行可能なスレッドのスレッド状態。実行可能状態のスレッドはJava仮想マシンで実行されていますが、オペレーティングシステムからの他のリソースを待機している可能性がありますプロセッサなど。
これはまさに起こっていることです。実際、スレッドはOS epoll_wait()
呼び出し内でブロックされています。 Linuxボックスでは、それが事実であることを確認する方法がいくつかあります。
strace
'ingスレッド_$ strace -tttT -f -p [thread-id]
_
スレッドIDはjstack
出力から取得できます。
_$ jstack [Java-pid]
[...]
"Netty Builtin Server 1" #17 prio=5 os_prio=31 tid=0x00000001013dd800 nid=0xe12f runnable [0x0000700001fe4000]
Java.lang.Thread.State: RUNNABLE
at Sun.nio.ch.KQueueArrayWrapper.kevent0(Native Method)
at Sun.nio.ch.KQueueArrayWrapper.poll(KQueueArrayWrapper.Java:198)
[...]
_
この場合、スレッドIDは_0xe12f
_です(10進数に変換する必要があります)。ほとんどの場合、スレッドはepoll_wait()
呼び出しにあります。
pidstat
ingスレッド_$ pidstat -tu -p [Java-pid] | grep [thread pid]
_
このスレッドにより、システムとユーザーのCPU時間が少なくなり、CPUを消費しなくなります。
ps
を使用したスレッド状態のポーリング_$ ps -eL -o pid,tid,state | grep [thread-id]
_
ほとんどの場合、スレッドはS
(実行可能)ではなく、状態Sl
またはR
(中断可能なスリープ)になります。
結局、サービスに運用上の問題がなければ、それについて心配する必要はありません。
参照されているリンクされた質問からの回答と同様に、一般的な問題は古いJDKのバグです。現在、更新されたバージョンを使用しているため、これは実際にはハードウェアのボトルネックである可能性があると思います。
これは、ハードウェア(ネットワークとサーバー)が問題の原因である可能性について説明しているGlassfishの問題へのリンクです。
また、これはまだ答えのない別の同様の質問です: SelectorImplはブロックされています
まず、両方のアプリケーションで同じ問題が発生するのは良いことです。おそらく、問題がアプリケーションではなく、JVMまたはOSのいずれかにあることを示しています:-)
Jzdが述べたように、nio.select()
には問題がありました。 {Javaのさまざまなバージョン} x {さまざまなプラットフォーム、カーネルバージョン}の乗算は、あらゆる場所の問題のように見えます。私はあなたのためにこれらの作品の1つを願っています:
Linuxを使用している場合は、2.6
を使用している場合に備えて、2.4
カーネルを試してください。
、バグが次のようになっていると仮定します: http://bugs.Sun.com/view_bug.do?bug_id=6670302
最新バージョンではなく、古いバージョンのJRE/JDKを使用してください!
、つまり、7ではなくJRE 6/JDK6に戻ります。
試してみてください
{older、newer}や{newer、older}のようにそれらを混同する代わりに。
1つのアプリが10,000の接続をポーリングし、接続ごとに使用するCPUはごくわずかですが、合計するとCPU時間のかなりの部分になる可能性があります。すべての優先事項は、他のジョブを最初に並べることです。
接続数は少ないが接続あたりのクランチが多い他のアプリでも、高い割合を示す可能性がありますが、待機時間の割合が低く、CPUの割合が高いはずです。