事例に学ぶWebシステム開発のワンポイント(1)

クラスタ化すると遅くなる?
― HttpSessionへの積み過ぎに注意 ―

(株)NTTデータ
COEシステム本部
池田寛治
2002/3/9


本連載では、現場でのエンジニアの経験から得られた、アプリケーション・サーバをベースとしたWebシステム開発における注意点やヒントについて解説する。巷のドキュメントではなかなか得られない貴重なノウハウが散りばめられている。読者の問題解決や今後システムを開発する際の参考として大いに活用していただきたい。(編集局)


今回のワンポイント
単体では良好なレスポンスを返していたWebシステムが、クラスタ化したとたん遅くなった。その原因は、HttpSessionにオブジェクトを格納しすぎたことにあった。しかし、アプリケーションの変更はできなかったため、レプリケーションされるオブジェクトを限定することで解決を図った。


運用環境でクラスタ構成の性能が出ない

今回の内容
運用環境でクラスタ構成の性能が出ない
原因はHttpSessionへの情報の積み過ぎ
WebLogicクラスタの制約
レプリケーションされるオブジェクトを限定することにより解決

 ある金融機関向けのシステムにおいて、マシン単体での性能試験では何ら問題がなかったのに、運用環境で試験すると大幅な性能劣化が起きるという事象があった。このシステムは、金融取引業務の一部を行うシステムで、Webサーバ、アプリケーション・サーバ(WebLogic)、DBサーバで構成されている。また、それぞれのマシンが2台ずつ用意されており、アプリケーション・サーバ、DBサーバともクラスタ化されている。もちろん、アプリケーション・サーバにはWebLogicクラスタが導入されていた。

WebLogic Serverで構成された、金融取引業務の一部を行うシステム。パフォーマンスと可用性の確保のため、クラスタ構成を採用

 運用環境にしただけで問題が出るということで、当初、ネットワークやマシンの設定が疑われたものの、調べた結果、アプリケーションに問題があり、クラスタ化されたことが性能劣化の原因であることが判明した。

原因はHttpSessionへの情報の積み過ぎ

 問題のアプリケーションは、多くのWebアプリケーションがそうであるように、ServletのHttpSessionを用いてユーザーのログイン管理を行っていた。ユーザー名などの情報をHttpSessionに格納することによって、クライアントからのリクエストがログイン済みのものかどうか、またどのユーザーのログインかを識別していたのである。また、WebLogicクラスタを利用することで、2台のアプリケーション・サーバのどちらかがダウンしたとしても、もう一方のアプリケーション・サーバがHttpSessionの情報を引き継ぎ、処理を継続できるように設計されていた。

 加えて、このアプリケーションはHttpSessionに画面のキャッシュ情報を格納していた。同一セッションで同じ画面に対するリクエストが起きたとき、その表示を高速化することが狙いであった。画面のキャッシュ情報はかなり大きなサイズであったが、メモリが十分に確保されているため、特に問題はないと考えられていた。事実、1台のサーバで試験を行ったときは何ら問題がなかった。ところが、クラスタ構成のWebLogicではHttpSessionに格納されているオブジェクトは、クラスタを構成するサーバ間でレプリケーションが行われる*1。このため、HttpSessionへの格納オブジェクトのサイズが大きいとレプリケーションに時間がかかり*2、大幅に性能が低下することにつながった。

*1:厳密には、クラスタを構成するサーバが3台以上ある場合は、その中の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);
%>

*3:厳密には、userInfoが初めて作成される場合はJSPのコード内でsetAttributeが呼び出されるため、レプリケーションが行われる。すでに存在するuserInfoを更新する場合に、明示的なsetAttributeが必要となる。
*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には大きな(そして複雑な構造の)オブジェクトを格納しないよう気を付けたい。

 

INDEX
事例に学ぶWebシステム開発のワンポイント
第1回 クラスタ化すると遅くなる?(2002/3/9)
  第2回 キャッシュが性能劣化をもたらす“なぞ”を解く(2002/3/23)
  第3回 クラスタは何台までOK?(2002/4/19)
  第4回 マルチスレッドのいたずらに注意(2002/5/14)
  第5回 サービス中にアプリケーションを入れ替える(2002/6/4)
  第6回 APサーバからの応答がなくなった、なぜ?(2002/11/30)
  第7回 低負荷なのにCPU使用率が100%?(2002/12/11)
  第8回 文字化け“???”の法則とその防止策(2003/1/28)
  第9回 メモリは足りているのに“OutOfMemory”(2003/2/15)
  第10回 レスポンスキャッシュでパフォーマンス向上(2003/3/29)
  第11回 JDBC接続を高速化する(2003/4/18)
  第12回 ブラウザキャッシュでパフォーマンス向上(2003/5/10)
  第13回 ファイルアップロード/ダウンロードに潜むわな(2003/6/12)


筆者プロフィール
池田 寛治(いけだ かんじ)

現在、株式会社NTTデータ COEシステム本部に所属。 技術支援グループとして、J2EEをベースにしたWebシステム開発プロ ジェクトを対象に、技術サポートを行っている。特に、性能・信頼性といった方式技術を中心に活動中。


Java Solution全記事一覧




Java Agile フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Java Agile 記事ランキング

本日 月間