私と私のチームは、クラスター化されたColdFusionアプリケーションを過去6か月の大部分の間安定させるのに苦労してきましたが、結果はほとんどありませんでした。 JRunの専門家や新鮮なアイデアを見つけて、それを理解できないようになることを期待して、SFに目を向けています。
セットアップ:
Windows Server2003ではIIS 6)でJRun 4(最新の更新プログラム付き)でクラスター化された2つのColdFusion 7.0.2インスタンス。2つのクアッドコアCPU、8GBのRAM。
問題:
時々、通常は週に1回、インスタンスの1つがリクエストの処理を完全に停止します。これまでのところアクティビティはなく、再起動する必要があります。
私たちが知っていること:
これが発生するたびに、JRunのエラーログは常にJava.lang.OutOfMemoryErrorでいっぱいになります:新しいネイティブスレッドを作成できません。
Macromedia/AdobeからのJRunドキュメントと多くの紛らわしいブログ投稿を読んだ後、インスタンスのjrun.xmlの誤った/最適化されていないJRunスレッドプール設定に多かれ少なかれ絞り込みました。
Jrun.xmlの関連部分:
<service class="jrun.servlet.jrpp.JRunProxyService" name="ProxyService">
<attribute name="activeHandlerThreads">500</attribute>
<attribute name="backlog">500</attribute>
<attribute name="deactivated">false</attribute>
<attribute name="interface">*</attribute>
<attribute name="maxHandlerThreads">1000</attribute>
<attribute name="minHandlerThreads">1</attribute>
<attribute name="port">51003</attribute>
<attribute name="threadWaitTimeout">300</attribute>
<attribute name="timeout">300</attribute>
{snip}
</service>
先週、JRunのメトリックロギングを有効にして、スレッドに関連するデータを収集しました。これは、1週間ログに記録した後のデータの要約です。
平均値:
{jrpp.listenTh} 1
{jrpp.idleTh} 9
{jrpp.delayTh} 0
{jrpp.busyTh} 0
{jrpp.totalTh} 10
{jrpp.delayRq} 0
{jrpp.droppedRq} 0
{jrpp.handledRq} 4
{jrpp.handledMs} 6036
{jrpp.delayMs} 0
{freeMemory} 48667
{totalMemory} 403598
{sessions} 737
{sessionsInMem} 737
最大値:
{jrpp.listenTh} 10
{jrpp.idleTh} 94
{jrpp.delayTh} 1
{jrpp.busyTh} 39
{jrpp.totalTh} 100
{jrpp.delayRq} 0
{jrpp.droppedRq} 0
{jrpp.handledRq} 87
{jrpp.handledMs} 508845
{jrpp.delayMs} 0
{freeMemory} 169313
{totalMemory} 578432
{sessions} 2297
{sessionsInMem} 2297
私たちが今何を試すことができるかについてのアイデアはありますか?
乾杯!
最大ヒープサイズは約1.4GBです。以前はリークがありましたが、修正しました。現在、アプリケーションは約400MBを使用しており、それ以上になることはめったにありません。最大ヒープサイズは1200MBに設定されているため、到達していません。リークが発生すると、JVMが爆発し、インスタンスが自動的に再起動します。これは現在発生していません。着信要求の処理を停止するだけです。
このブログ投稿に続くスレッドと関係があると考えていました: http://www.talkingtree.com/blog/index.cfm/2005/3/11/NewNativeThread
スローされるJava例外はOutOfMemory型ですが、実際にはヒープスペースが不足しているとは言っておらず、新しいスレッドを作成できなかっただけです。例外型は少し誤解を招く可能性があります。
基本的にブログでは、activeHandlerThreadsとしての500は高すぎる可能性があると言っていますが、私のメトリックは、混乱しているものに近いところがないことを示しているようです。
さて、JRun構成の詳細に入る前に、いくつかの全体像の問題を見てみましょう。
JRunエラーログでJava.lang.OutOfMemoryError例外が発生している場合は、メモリが不足しています。賛成しないでください;-)。 32ビットと64ビットのどちらのWindowsを実行しているかはわかりませんでしたが、8 GBのRAMがあると言ったので、答えにいくらかの影響があります。 32ビットまたは64ビットのJVMを実行しているかどうか(およびそのバージョン)も影響します。だから、これらは私たちがこれの底に到達するのに役立ついくつかの答えです。
とにかく、アプリケーションISメモリが不足しています。次の1つ以上の理由により、メモリが不足しています。
その他の注意事項:32ビットWindowsでは、32ビットJVMは約1.4GBのメモリしか割り当てることができません。 64ビットWindows上の32ビットJVMの制限が、32ビットプロセスの理論上の最大4 GB未満である場合、頭の中で思い出せません。
更新しました
TalkingTreeを介してリンクされているブログ投稿と、その投稿内にリンクされている他の投稿も読みました。私はこの正確なケースに遭遇していませんが、次の観察結果がありました。JRUNメトリックログは、スレッド使用のピーク時に引用した「最大値」を記録しない場合があります。一定の繰り返し間隔でメトリックをログに記録すると思います。これは、アプリケーションのスムーズで平均的なパフォーマンス特性を示すのに適していますが、エラー状態が発生し始める直前のJRUNの状態をキャプチャしない場合があります。
JRUNのスレッド管理の内部動作について知らなくても、それは本当にメモリ不足であると私は言います。アプリがJVMヒープにメモリを割り当てる必要があり、使用可能なものがなかったため、メモリ不足ではない可能性がありますが、JRUNが着信要求を処理するために別のスレッドを作成しようとし、別のスレッドをサポートするために必要なヒープメモリがなかったため、メモリ不足です。利用可能-言い換えれば、スレッドは無料ではありません-ヒープメモリも必要です。
オプションは次のようです。
追求するオプションに関係なく、ここでの有効な修正は本質的に実験的なものになると思います。変更を加えて、それがアプリケーションにどのような影響を与えるかを確認する必要があります。負荷テスト環境がありますよね?
試してreduce最大ヒープサイズ。各スレッドにはネイティブリソースが必要です(Java独自のものとともに)。使用可能な仮想ASは2GB、1.2GBはヒープ用に予約されています。残りの800MBの一部はコード(のテキストセグメント)に使用されます。 Javaおよび必要なすべてのDLL)、JREとその依存関係に必要なネイティブ割り当てがあります...そしてスレッド:デフォルトでは、スレッドごとに1MBのASが予約されています(1ページだけですが)実際にコミットされます)、100スレッド= 100MB(スタックの場合のみ)。ここで、さまざまな部分の間に少し余分なスペースを追加し、断片化します... OOM ;-)