クラスタ化すると遅くなる?― HttpSessionへの積み過ぎに注意 ―:事例に学ぶWebシステム開発のワンポイント(1)
本連載では、現場でのエンジニアの経験から得られた、アプリケーション・サーバをベースとしたWebシステム開発における注意点やヒントについて解説する。巷のドキュメントではなかなか得られない貴重なノウハウが散りばめられている。読者の問題解決や今後システムを開発する際の参考として大いに活用していただきたい。(編集局)
今回のワンポイント
単体では良好なレスポンスを返していたWebシステムが、クラスタ化したとたん遅くなった。その原因は、HttpSessionにオブジェクトを格納しすぎたことにあった。しかし、アプリケーションの変更はできなかったため、レプリケーションされるオブジェクトを限定することで解決を図った。
運用環境でクラスタ構成の性能が出ない
ある金融機関向けのシステムにおいて、マシン単体での性能試験では何ら問題がなかったのに、運用環境で試験すると大幅な性能劣化が起きるという事象があった。このシステムは、金融取引業務の一部を行うシステムで、Webサーバ、アプリケーション・サーバ(WebLogic)、DBサーバで構成されている。また、それぞれのマシンが2台ずつ用意されており、アプリケーション・サーバ、DBサーバともクラスタ化されている。もちろん、アプリケーション・サーバにはWebLogicクラスタが導入されていた。
運用環境にしただけで問題が出るということで、当初、ネットワークやマシンの設定が疑われたものの、調べた結果、アプリケーションに問題があり、クラスタ化されたことが性能劣化の原因であることが判明した。
原因はHttpSessionへの情報の積み過ぎ
問題のアプリケーションは、多くのWebアプリケーションがそうであるように、ServletのHttpSessionを用いてユーザーのログイン管理を行っていた。ユーザー名などの情報をHttpSessionに格納することによって、クライアントからのリクエストがログイン済みのものかどうか、またどのユーザーのログインかを識別していたのである。また、WebLogicクラスタを利用することで、2台のアプリケーション・サーバのどちらかがダウンしたとしても、もう一方のアプリケーション・サーバがHttpSessionの情報を引き継ぎ、処理を継続できるように設計されていた。
加えて、このアプリケーションはHttpSessionに画面のキャッシュ情報を格納していた。同一セッションで同じ画面に対するリクエストが起きたとき、その表示を高速化することが狙いであった。画面のキャッシュ情報はかなり大きなサイズであったが、メモリが十分に確保されているため、特に問題はないと考えられていた。事実、1台のサーバで試験を行ったときは何ら問題がなかった。ところが、クラスタ構成のWebLogicではHttpSessionに格納されているオブジェクトは、クラスタを構成するサーバ間でレプリケーションが行われる*1。このため、HttpSessionへの格納オブジェクトのサイズが大きいとレプリケーションに時間がかかり*2、大幅に性能が低下することにつながった。
*2:実際は、単にサイズが大きいだけでなく、ツリー状に数多くのオブジェクトが含まれる複雑な構造であったためSerializeに非常に時間がかかっていた。
WebLogicクラスタの制約
クラスタ化をやめれば性能問題は解決するものの、HttpSessionには画面のキャッシュ情報のみならず、ユーザーのログイン情報も格納されているため、クラスタ化は必須であった。また、時間の制約上アプリケーションの大幅な手直しもできなかった。そこで、クラスタを維持しつつもアプリケーションに大きな変更を行わない解決策を考えることとなった。
ところで、WebLogicクラスタでは、HttpSessionに格納しているオブジェクトをレプリケーションするには、明示的にsetAttributeメソッドを呼び出す必要がある。例えば、次のようなJSPコードを考えてみる。
<jsp:useBean id="userInfo" class="UserInfo" scope="session" /> <% userInfo.setName("Taro"); // このままではレプリケーションされない %>
このコードでは、sessionスコープにある(すなわちHttpSessionに格納されている)userInfoというオブジェクトに名前がセットされているが、このコードのままではuserInfoオブジェクトはレプリケーションされない*3。「WebLogic Serverクラスタガイド」の中に書かれてあるように*4、レプリケーションするには次のように明示的にsetAttributeを呼び出す必要がある。
<jsp:useBean id="userInfo" class="UserInfo" scope="session" /> <% userInfo.setName("Taro"); // レプリケーションするには、明示的なsetAttributeが必要 session.setAttribute("userInfo", userInfo); %>
*4:http://edocs.beasys.co.jp/e-docs/wls61/cluster/servlet.html#910202
レプリケーションされるオブジェクトを限定することにより解決
上記の制約は、WebLogicクラスタを利用するときの大きな注意点であるが、今回はこの制約を逆手に利用し、下記のように必要なオブジェクトのみがレプリケーションされるようにした。
<jsp:useBean id="userInfo" class="UserInfo" scope="session" /> <jsp:useBean id="screenCache" class="ScreenCache" scope="session" /> <% userInfo.setName("Taro"); screenCache.setCacheData(...); // レプリケーションするのはUserInfoのみ session.setAttribute("userInfo", userInfo); %>
この対策により、アプリケーションを大きく変更することなくレプリケーションされるオブジェクトを減らし、何とか性能目標を達成することができた。
HttpSessionはWebアプリケーション開発において、なくてはならない機能であり、多用しがちになるが、できるだけHttpSessionには大きな(そして複雑な構造の)オブジェクトを格納しないよう気を付けたい。
著者プロフィール
池田 寛治(いけだ かんじ)
現在、株式会社NTTデータ COEシステム本部に所属。 技術支援グループとして、J2EEをベースにしたWebシステム開発プロ ジェクトを対象に、技術サポートを行っている。特に、性能・信頼性といった方式技術を中心に活動中。
- ファイルアップロード/ダウンロードに潜むわな− 大容量、高負荷時の注意点 −
- ブラウザキャッシュでパフォーマンス向上―負荷分散装置の落とし穴に注意−
- JDBC接続を高速化する− PreparedStatementキャッシュの威力−
- レスポンスキャッシュでパフォーマンス向上―アプリケーションを変更せず性能UPする魔法のつえ―
- メモリは足りているのに“OutOfMemory”
- 文字化け“???”の法則とその防止策
- 低負荷なのにCPU使用率が100%?
- APサーバからの応答がなくなった、なぜ?―GCをチューニングしよう―
- サービス中にアプリケーションを入れ替える―クラスタ機能を活用しよう―
- マルチスレッドのいたずらに注意―あなたのJSPやServletは大丈夫?―
- クラスタは何台までOK?―性能から見たWebLogicクラスタの適正台数―
- キャッシュが性能劣化をもたらす“なぞ”を解く― データのキャッシュとコネクションプール ―
- クラスタ化すると遅くなる?― HttpSessionへの積み過ぎに注意 ―
Copyright © ITmedia, Inc. All Rights Reserved.