3

Tomcat Webアプリケーションは、数百人のユーザーが使用すると遅く感じます。サーバーはホスティング会社に属しており、レポートには帯域幅やCPU負荷に関する問題はないので、私は同期コールでカプセル化したいくつかのレガシーコードの競合が原因である可能性があると考えています。より簡単なパス。javaで同期化された競合の証拠を探す場所は?

私はThreadLocalソリューションで同期化された呼び出しを変更する開発環境でいくつかの人工的なテストを行っていますが、速くなりますが、私の上司には生産時にも速くなるという証拠が必要です。

私のアプリでスレッドの競合が問題になるかどうかはどうすればわかりますか?

答えて

7

最近のJava 6 JDKに付属しているvisualVMツールのビューでは、あなたの理論の確かな証拠を提供することができます。各スレッドの円グラフが表示され、実行中、スリープ中、待機中、モニター内でどれくらいの時間が費やされているかが示されます。 (赤色で表示)最後は、あなたが興味を持っているものです:

alt text

0

私はこの

//... 
long t0 = System.currentTimeMillis(); 
synchronized(lockObj){ 
    logger.info("T sync :" + (t0 - System.currentTimeMillis())); 
    //... 
} 

のように私たちの同期の呼び出しでロギングを追加することもできますが、これは安くて汚い感じています。

+1

有効数字を取得するには、currentTimeMillis()ではなくnanoTime()を使用する必要があります。 –

+1

この種のロギング>>は、システムの動作を変更する可能性があることに注意してください。例えばSystem.currentTimeMillis()またはlogger.info(...)を呼び出すと、コンテキスト切り替えが発生します。 –

3

あなたが変更したバージョンの方が速い場合は、いくつかの負荷テスター(例:JMeter)を使って両方のバージョンをテストしてテストします。重要な違いがある場合は、それを証明する結果が得られます。

+0

ありがとうございますが、この種のテストを実行するための本番環境と同じ設定の適切な統合環境はありません。開発時のJMeterテストの実行は、すでに行ったテストと同じです。 – Serxipc

1

貴重品は、のようにお金がかかるかもしれない他のものと同様に、open source java profilersの束です。既存のコードと拡張コードの両方でテストを実行する必要があります。 ThreadLocalsを使った作業は一般的に競合を減らすはずですが、最適化を開始する前にベンチマークを行うことも良いと考えています。

プロファイラを設定せずに行うことができるもう少し簡単なテストは、アプリケーションが遅いと思われる間にいくつかのスレッドダンプ(ctrl-breakまたはkill -QUIT)を実行することです。時間の短いペースで同じまたは同じモニターを待っているいくつかのスレッドを検出すると、遅い場所をはっきりと指摘することができます。 Javaスレッドダンプアナライザであるtools like TDAを使用すると、スレッドダンプの処理に役立ちます。

この場合も、最適化を開始する前にこの作業を行うことをお勧めします。これは、最適化によって差異が生じる可能性のある明示的な場所がいくつか存在する可能性がありますが、実際のユーザーの動作によって開発者が考慮しないパスがトリガされ、これらが実際の問題領域になる可能性があるからです。

+0

Eclipse TPTPとNetbeansを使用する前に、アプリケーションの一部をプロファイリングしましたが、アプリケーション全体のプロファイリングが非常に遅くなり、クラッシュしなければ何時間もかかるため、負荷テスト中にプロファイリングを試みたことはありませんでした。 – Serxipc

+1

ええ、それはプロファイラーの下に大きなアプリを置くのを面倒な仕事にすることができます。マイケル・ボルグワルトのツールは有望だ​​と示唆している。 – akf

0

あなたの分析は合理的です。あなたはあなたに添付できますか? (JDK内の)visualvmをプロセスに渡すと、どこで時間が費やされているのかを確認できます。

1
jstack PID 

スレッドのステータスに関する情報とともに、プロセスID PIDとJVMの状態のリストを出力します。

サンプル出力(抜粋):

"AWT-XAWT" daemon prio=10 tid=0x0000000000e5f800 nid=0x476d runnable [0x00007f1a75616000..0x00007f1a75616bf0] 
    java.lang.Thread.State: RUNNABLE 
    at sun.awt.X11.XToolkit.waitForEvents(Native Method) 
    at sun.awt.X11.XToolkit.run(XToolkit.java:543) 
    at sun.awt.X11.XToolkit.run(XToolkit.java:518) 
    at java.lang.Thread.run(Thread.java:636) 

"Java2D Disposer" daemon prio=10 tid=0x0000000000d8b800 nid=0x476c in Object.wait() [0x00007f1a759df000..0x00007f1a759dfc70] 
    java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <0x00007f1a82e2c3f8> (a java.lang.ref.ReferenceQueue$Lock) 
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:133) 
    - locked <0x00007f1a82e2c3f8> (a java.lang.ref.ReferenceQueue$Lock) 
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:149) 
    at sun.java2d.Disposer.run(Disposer.java:143) 
    at java.lang.Thread.run(Thread.java:636) 

私はまた、競合の下にリソースを隔離しようと思います。例えばレガシーライブラリがロックしていて、データベースへの書き込みをsyncrhonizeしていると、書き込みを最小限に抑えることができます。

関連する問題