本連載では、現場でのエンジニアの経験から得られた、アプリケーション・サーバをベースとしたWebシステム開発における注意点やヒントについて解説する。巷のドキュメントではなかなか得られない貴重なノウハウが散りばめられている。読者の問題解決や今後システムを開発する際の参考として大いに活用していただきたい。(編集局)
単体では良好なレスポンスを返していたWebシステムが、クラスタ化したとたん遅くなった。その原因は、HttpSessionにオブジェクトを格納しすぎたことにあった。しかし、アプリケーションの変更はできなかったため、レプリケーションされるオブジェクトを限定することで解決を図った。
ある金融機関向けのシステムにおいて、マシン単体での性能試験では何ら問題がなかったのに、運用環境で試験すると大幅な性能劣化が起きるという事象があった。このシステムは、金融取引業務の一部を行うシステムで、Webサーバ、アプリケーション・サーバ(WebLogic)、DBサーバで構成されている。また、それぞれのマシンが2台ずつ用意されており、アプリケーション・サーバ、DBサーバともクラスタ化されている。もちろん、アプリケーション・サーバにはWebLogicクラスタが導入されていた。
運用環境にしただけで問題が出るということで、当初、ネットワークやマシンの設定が疑われたものの、調べた結果、アプリケーションに問題があり、クラスタ化されたことが性能劣化の原因であることが判明した。
問題のアプリケーションは、多くのWebアプリケーションがそうであるように、ServletのHttpSessionを用いてユーザーのログイン管理を行っていた。ユーザー名などの情報をHttpSessionに格納することによって、クライアントからのリクエストがログイン済みのものかどうか、またどのユーザーのログインかを識別していたのである。また、WebLogicクラスタを利用することで、2台のアプリケーション・サーバのどちらかがダウンしたとしても、もう一方のアプリケーション・サーバがHttpSessionの情報を引き継ぎ、処理を継続できるように設計されていた。
加えて、このアプリケーションはHttpSessionに画面のキャッシュ情報を格納していた。同一セッションで同じ画面に対するリクエストが起きたとき、その表示を高速化することが狙いであった。画面のキャッシュ情報はかなり大きなサイズであったが、メモリが十分に確保されているため、特に問題はないと考えられていた。事実、1台のサーバで試験を行ったときは何ら問題がなかった。ところが、クラスタ構成のWebLogicではHttpSessionに格納されているオブジェクトは、クラスタを構成するサーバ間でレプリケーションが行われる*1。このため、HttpSessionへの格納オブジェクトのサイズが大きいとレプリケーションに時間がかかり*2、大幅に性能が低下することにつながった。
クラスタ化をやめれば性能問題は解決するものの、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); %>
上記の制約は、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システム開発プロ ジェクトを対象に、技術サポートを行っている。特に、性能・信頼性といった方式技術を中心に活動中。
Copyright © ITmedia, Inc. All Rights Reserved.