WAS 小ワザ集

第17回:Application Anti Pattern(4) 操作する際にロックがかかるクラスをHttpSessionにいれる

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: WAS 小ワザ集

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:WAS 小ワザ集

このシリーズの続きに乞うご期待。

Anti Pattern

あるアプリケーションは、HttpSessionにjava.util.Collections#synchronizedSet()メソッドで作成したSynchronizedSetを格納していました。

また、別の箇所ではHttpSessionから取り出したSynchronizedSetにロックをかけたsynchronizedブロックがあり、そのなかでHttpSessionの操作をしていました。

Result

このアプリケーションは、シングル環境で動作させているうちは問題ありませんでした。ですが,複数アプリケーションサーバーからなるクラスター環境で動かしたところ、内部でデッドロックが発生してアプリケーションが停止してしまいました。

デッドロックの発生メカニズムはこうです。

クラスター環境では、アプリケーションサーバー間でセッションを共有するため、HttpSessionの内容物をシリアライズして外部に送信します。この処理を行う際に、WAS(WebSphere Application Server)のセッションマネージャーは対象のHttpSessionをロックします。またSynchronizedSetはシリアライズされる際に自身のロックをかけるようになっています。そのため、セッションの送信時にHttpSession→SynchronizedSetの順で二重ロックがかかります。

一方アプリケーションではSynchronizedSetにロックをかけた状態でHttpSessionを操作しています。その操作のなかには、WAS内部でHttpSessionにロックがかかる処理がありました。そのためSynchronizedSet→HttpSessionの順で二重ロックがかかっていました。

Javaプログラムの中に、異なる順序で二重ロックをかける箇所があると、タイミングによってデッドロックが発生してしまいます。特にこのケースではデッドロックの片方がWASのセッションマネージャーであったため、他のスレッドからもHttpSessionの操作ができなくなるなど深刻な障害となってしまいました。この状況は、アプリケーションサーバーを再起動するまで解消されませんでした。

Best Practice

HttpSessionに、操作の際にロックがかかるオブジェクトを格納する際には注意が必要です。とくにtoString()やhashCode()、writeObject()メソッドなどが同期化(synchronized)されている場合に問題が発生する可能性が高くなります。

このようなオブジェクトとしては、Collections#synchronizedSet()やCollections#synchronizedMap()、Collections#synchronizedCollection()などで作成したオブジェクトや、StringBufferのインスタンスなどがあります。

このようなオブジェクトを格納している際には、それらのオブジェクトにロックをかけたままHttpSessionの操作をしないで下さい。

またHttpSessionを安全につかうためには、なるべくStringやIntegerなどの変更不能クラス(Immutable Class)のインスタンスだけを格納するようにします。アプリケーションでロックの対象としているオブジェクトへの参照を、フレームワークやライブラリなど外部のプログラムにわたすことも極力避けるようにしましょう。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=WebSphere
ArticleID=806647
ArticleTitle=WAS 小ワザ集: 第17回:Application Anti Pattern(4) 操作する際にロックがかかるクラスをHttpSessionにいれる
publish-date=03282012