L
o
a
d
i
n
g
.
.
.

ホーム

お知らせ

製品・ソリューション

サービス

導入事例・パートナー

EXEM Academy・ブログ

会社情報

採用情報

2022.09.22

同期によるThread Deadlock

同期によるThread Deadlock

(株)エクセムコンサルティング本部/APM支援チーム

Javaオブジェクトやメソッドの同時実行制御のための同期技術を誤って使用したときに現れるスレッド間のデッドロックによるトランザクション遅延の状況を見てみましょう。

 マルチスレッド環境で共有オブジェクトの演算を行うブロックに synchronized を使用する場合、そのオブジェクトの read, write 操作はすべて直列化され、最初に同期されたブロックにアクセスした Thread の作業が終わるまで、他のスレッドは同じオブジェクト に対して書き込みはもちろん、読み込み作業でも実行できない状態になります。

 これらの制約自体だけでパフォーマンスに影響を与えることは、特段説明する必要はないでしょう。

同期技術を使用するときに発生するパフォーマンス問題の中で最も大きな問題が、まさにスレッド間のデッドロック現象です。

共有オブジェクトであるAオブジェクトとBオブジェクトが存在すると仮定すると、A、Bオブジェクトを相互参照する演算を実行する同期ブロックを持つ2つのアプリケーションが存在する場合Deadlock が発生しますが、この問題を防止するためには、同期ブロック内の演算実行範囲を最小化し、A,B オブジェクトの参照順序を同じにするか、A,B オブジェクトを参照する別個のオブジェクトを生成して使用するようなロジックの修正が必要です。

この他にも、Java5.0 から新たにサポートされる同期技術である Lock Interface を使用して Deadlock の状況を最小化し、パフォーマンス改善を図ることもできます。

 しかし、このLock Interfaceの使用もDeadlockの発生を源泉的に防ぐことはできません。 Deadlockは、同期技術を誤って活用したときに発生するという点で、ロジック設計および開発時にソース修正段階で共有オブジェクトへの同期化を使用するアプリケーションの確実な検証を経ていないことが原因となる場合がほとんどです。やはりこの問題の解決は、開発段階から相互交差参照をしないようにロジックを実装する方法が唯一であることになります。

基本的にJAVAでは、スレッドは異なるスレッドの操作に影響を与えずに独立して実行できるように実装されています。

< ThreadとAオブジェクトのメソッド間のアクセス関係>

図に示すように、各 Thread は A オブジェクトのすべての public Method に対して重複アクセスが許可されます。

これは、WASの目的であるWebサービス環境で多数の要求を効率的に処理するための目的に由来します。

つまり、シリアル処理から来る限界点を克服するために、すべてのスレッドがそれぞれの要求を別々に実行できるように並列処理が可能に実装されているからです。

しかし、このようなWAS環境でも直列処理が必要な状況が明らかに存在します。

 単に保存されているデータを表示するための操作ではなく、データを修正しなければならない状況が来ると、それに加えて、そのデータは、WASにアクセスするすべての要求に対して唯一性を持つ共有データであれば問題が変わることになります。

 すなわち、同期技術が適用されるべきです。

このパターンをシングルスレッド実行と呼びますが、このパターンを実装するために最も一般的に使用されるのは同期技術です。

Synchronized で宣言されたオブジェクトやメソッド、またはメソッド内のブロックに Thread がアクセスするためには monitor と呼ばれる Lock を取得しなければなりません。

 このようなロックを通じて、該当データに対して一意性を保証し、シリアル処理を可能にします。


<Synchronized技術を使用した場合>

B Method が Synchronized に指定されている場合、以前とは異なり、① Thread が B Method の数行を終了するまで ②Thread は待機します。

これは、B Methodにmonitor Lockが実装されているため、B Methodが非常に頻繁に実行され、実行に時間がかかるメソッドであれば、Transactionの実行パフォーマンスに非常に悪い影響を与える可能性があります。 そのため、一般的に Synchronized で宣言する場合は、該当オブジェクトやメソッド、ブロックの実行範囲を最小化することを推奨しています。

Synchronized技術で発生する可能性があるもう1つの問題は、まさにDeadlockです。 Deadlockは、相互排他的なアクセスを同時に実行しようとしたときに発生する現象です。 ②がBオブジェクトに対してモニタロックを獲得し、演算を実行する途中でAオブジェクトのモニタロックをキャッチするのを待つ状況が発生する。 このようにお互いがお互いのロックを先に解除するだけを待っている状況がまさにDeadlock現象です。

< Thread Deadlockの状況>

ThreadがDeadlockの状況に陥ると、他方のモニターロックを獲得するために無限に待機することになります。

このようなトランザクションが頻繁に行われると、しばらくの間利用可能なスレッドがすべて使い果たされ、サービス障害の状況になります。

 Synchronized を使用しなければならない環境で Deadlock を回避する方法は、とにかく単純で簡単です。 Synchronizedで同期されたリソースについて、どのアプリケーションでも常に同じ順序で参照するようにすればよいのです。上記の状況でB、Cメソッドを実行するすべてのアプリケーションがBメソッドを実行した後にCメソッドを実行するように編成されている場合、Deadlockは決して発生しないのです。

これは、ほとんどのDeadlockがロジックの設計過程や実際の実装段階での錯誤で発生するものであるため、未然に防止が可能であることを意味します。

そして、もし発生したとしても、以下の方法を通じてどのようなアプリケーションによって発生したのかを把握することができれば、難しくない措置が可能です。

▶ JVM Thread Dump

Thread Dump は、特定の時間に JVM 上で実行中の Thread の状態情報に対する一種の snapshot で Transaction が遅れた時点で Thread Dump をみれば、その時各 Thread がどのようなことを実行し、どのような状態にあるか把握できるように多くの情報を提供しています。

コマンドを使用する。 Dump の結果は Console に出力されるため、Redirection を介してファイルに保存して使用するようにします。

上記は、Thread Dumpのうちの1つのThreadの情報だけを選んだものです。 各項目について見てみると

1.     Thread Name : Thread の名前を表す。 (WASベンダーによって表示される形式が少し異なります。)

  • Thread id : system で付与された Thread ID
  • Thread status : Thread の実行状態情報(JVM 別)
  • Stack Trace : 当時の Thread で実行中の Class Method 実行情報

大きく4つの領域に分かれていますが、各領域が含まれている内容はWASベンダーとJVMの種類別に少しずつの違いがあるので基本的な意味だけ理解できれば良いです。

上記のスレッドダンプの内容を大まかに解釈すると、ダンプ実行時にhttp1-w19という名前を持つスレッドID 0x08e718b0のスレッドがモニタエントリにアクセスするために待機し、

実行中の Class Method は sfairPkg.Dlock.run3 で、0xeffc9ce8 オブジェクトの monitor

ロックを獲得しようとしていることがわかります。

このように、Thread Dump を利用すれば、その時の WAS のすべての Thread の状態情報を得ることができ、 Transaction 遅延の原因を探す上で重要な手がかりが提供されるので、 Transaction 処理が遅くなる時点で 1~2 秒間隔で 2~3 回程度 のDumpを取っておけば事後分析に有用に活用できます。

これらのスレッドダンプは基本的にテキスト形式で受け取ることができますが、分析するのは簡単ではないので、GUIを介してより簡単に分析できるようにするパブリックプログラムを使用することをお勧めします。

これらのツールの中で使いやすいThread Dump分析専用プログラムである「SAMURAI」の使い方について簡単に説明します。.

‘SAMURAI’は「Yusuke Yamamoto」という日本人が製作したDump分析ツールで、Thread Dump、GC Dumpなどを簡単に分析できるようにするプログラムです。 「SAMURAI」のホームページに行ってプログラムを直接実行してみることもできますし、PCにダウンロードしてjava –jre samurai.jarコマンドを通じて実行することもできます。

< SAMURAI実行画面>

このツールはhttp://yusuke.homeip.net/samurai/en/index.html#threadDumpAnalysisから ダウンロードして使用することができます。

プログラムを実行すると空の画面が表示されますが、使い方も非常に簡単です。 受け取った Thread Dumpテキストファイルをドラッグしてアップロードするか、File>Openメニューから読み込むだけです。

<スレッドダンプ解析後画面>

Thread Dumpファイルを読み込んだ後に2つのTabが生成され、そのうちLog TabはDumpの内容を見ることができるメニューで、Thread DumpsはDumpの内容を分析してThreadの状態をテーブルの形で示すメニューです。

<スレッド状態表示画面>

画面の左側はThread Listを示し、右側は各ThreadのDump当時の状態を色で表している。 Deadlockはスケルトン図で表示され、わかりやすく表現しています。

<デッドロック状態のスレッド情報〉

結論

このように問題発生時の Thread Dump は Transaction 遅延原因分析に多くの手がかりを提供してくれるため、障害発生時や Transaction 遅延時には Dump を取得することが管理面で非常に有用です。

 今回紹介した「SAMURAI」プログラムは、簡単ながら分析に必要なThread状態情報をわかりやすく表現してくれています。

この他にも、各OS JVMベンダーごとに独自に提供する有用な分析プログラムがたくさんありますが、これを十分に活用すれば、ほとんどのパフォーマンス遅延の原因を難しくなく分析することができるでしょう。


PHP Code Snippets Powered By : XYZScripts.com