Tomcatクラスタ-1

mod_proxy_ajp を使用して Apache と連携する



(2007/07/12)
動作環境

 このページでは以下の環境での動作を説明しています。
Debian Linux Etch
Apache2.2.3
Tomcat5.5
J2SDK 5.0 Update10
mod_proxy_ajp

 今まで、ApacheとTomcatの連携といえばmod_jkを使用するのが一般的でした。しかし、最近のApacheにはmod_proxy_ajpというモジュールが標準で付属し、これを用いて連携が行えるようになりました。
 mod_proxy_ajpは単体ではなくmod_proxyと連係することで動作します。
設定

 設定はmod_jkを用いたものより、簡易になっています。
 /etc/apache2/mods-availableに、新規にproxy_ajp.confファイルを作成します。
<IfModule mod_proxy_ajp.c>
   <Location /jsp-examples/>
       ProxyPass ajp://localhost:8009/jsp-examples/
   </Location>
</IfModule>

 デフォルトのmod_proxyの設定は、全拒否になっていますので修正します。
<IfModule mod_proxy.c>
   #turning ProxyRequests on and allowing proxying from all may allow
   #spammers to use your proxy to send email.

   ProxyRequests Off

   <Proxy *>
       AddDefaultCharset off
       Order deny,allow
       Deny from all
       #Allow from .example.com
       Allow from 192.168.1.0/255.255.255.0
   </Proxy>

   # Enable/disable the handling of HTTP/1.1 "Via:" headers.
   # ("Full" adds the server version; "Block" removes all outgoing Via: headers)
   # Set to one of: Off | On | Full | Block

   ProxyVia On
</IfModule>

 mod_proxy_ajpを有効にします。
debian:~# a2enmod proxy_ajp


Tomcat でクラスタリングを構成する


(2007/07/12)
動作環境

 このページでは以下の環境での動作を説明しています。
Debian Linux Etch
Tomcat5.5
J2SDK 5.0 Update10
クラスタリングとは

 クラスタリングとは複数のマシンを連携させることで、処理速度、稼働時間を向上させる技術です。クラスタリング構成がされたシステムは外部から見た場合、一台のマシンと同様に動作します。
 Tomcatにおいてクラスタリングを行うことで、複数のTomcat間でセッション内の情報を同期するようになります。
設定

 Tomcatをそれぞれ複数のマシンで動作させる場合、設定は簡易です。/etc/tomcat5.5/server.xmlの<Cluster縲廚luster>のコメントアウトを外すだけ設定が完了します。
 もし、一台のマシンで複数のTomcatを動かしてクラスタリングを試してみたいという場合は、ポート番号が当たってしまうため、ずらす必要性があります。具体的には<Cluster>→<Receiver>のtcpListenPortおよび、<Server>のport。<Connector>の各種ポート番号の変更が必要でしょう。
 設定を終えてTomcatをそれぞれ起動すると、マルチキャストで通信しあってお互いを見つけ出し、自動的にクラスタリングを構成します。
Tomcatクラスタリングの注意点

  • オブジェクトをセッションに格納する

 異なるTomcat間でセッションに格納されたオブジェクトを共有できると言うことは、それらのオブジェクトが複製可能であることを意味します。そのため、セッションに格納するオブジェクトはSerializableインターフェイスをインプリメントしておく必要があります。つまりセッションの同期化とはオブジェクトの直列化を利用してセッション内のオブジェクトを送受信し、コピーしあうことと言えます。
 クラスタリング下のTomcatではSession#setAttributeでセッションに格納したオブジェクトをSession#getAttributeで取り出したとしても、そのオブジェクトの同一性は保証されません。
request.getSession().setAttribute("shareData", data);
data2 = request.getSession().getAttribute("shareData");
if (data == data2) { // ここがtrueになるとは限らない
   System.out.println("same object");
}
 またSessionオブジェクト自体の同一性も保証されません。
  • セッション同期のタイミング

 Tomcatのクラスタリングではセッション内の情報は、常に監視されていているわけではありません。セッションが同期するタイミングが存在します。
 セッション同期のタイミングはserver.xmlでの設定によって変更されます。<Cluster>要素の属性値であるuseDirtyFlagがそれです。useDirtyFlagが"true"の場合、SessionオブジェクトのgetAttributeメソッドおよびremoveAttributeが呼ばれたときに同期化が行われます。"false"の場合、リクエストの最後にセッションの同期化処理が行われます。


クラスタ構成の Tomcat をApacheでロードバランスする



(2007/07/18)
動作環境

 このページでは以下の環境での動作を説明しています。
Debian Linux Etch
Apache2.2.3
Tomcat5.5
J2SDK 5.0 Update10
ロードバランサの必要性

 Tomcatでクラスタリングを行うことで、セッション情報の共有が行われます。これによって使用中のTomcatがダウンしても、別のTomcatに接続することでセッションを継続することができるはずです。
 しかし、これは現実的でありません。使用中のTomcatが動作を停止したとき、ユーザーはブラウザのURLを手で書き換えて稼働中のTomcatに明示的につなぎに行く必要があります。しかも、通常セッションIDはcookieに格納されています。これではURLが変更した場合セッションIDが取得できません。つまり、cookieが無効になっていてURLにセッションIDが組み込まれているときに、手作業でURLを書き換えることでしか、セッションを継続できません。
 そこで、Apacheをロードバランサとして使用することで、この問題を解決します。Apacheを中継することで接続先のURLはApacheのURLのみとなります。障害時にはApacheがTomcatサーバの死活を判断し、動作しているTomcatに処理を割り振ります。
mod_proxy_balancer

 Tomcatのロードバランスには以下のモジュールを使用します。
mod_proxy
mod_proxy_ajp
mod_proxy_balancer
 mod_proxyの設定はmod_proxy_ajp を使用して Apache と連携するを参考にしてください。
 ロードバランサの設定はproxy_ajp.confに記述することにします。
<IfModule mod_proxy_ajp.c>
<IfModule mod_proxy_balancer.c>
   <Location /ClusterSample/>
       ProxyPass balancer://ClusterSample/ nofailover=Off
   </Location>

   <Proxy balancer://ClusterSample/>
       BalancerMember ajp://192.168.0.1:8009/ClusterSample/ loadfactor=10
       BalancerMember ajp://192.168.0.2:8009/ClusterSample/ loadfactor=10
   </Proxy>

</IfModule>
</IfModule>
StickySession

 以上の設定でTomcatを動作させると、毎回アクセスするサーバーが変更されます。(JSPに各々サーバ名を記述するなどして、どのサーバを使用して表示されてるいるのかわかるようにしてみてください)
 しかし、最初に使用したサーバを使用し続け、障害時にのみ別のサーバに切り替わるようにしたい場合もあると思います。その場合はStickySessionを利用することで実現できます。

 proxy_ajp.confに設定を追加します。
<IfModule mod_proxy_ajp.c>
<IfModule mod_proxy_balancer.c>
   <Location /ClusterSample/>
       ProxyPass balancer://ClusterSample/ stickysession=JSESSIONID nofailover=Off
   </Location>

   <Proxy balancer://ClusterSample/>
       BalancerMember ajp://192.168.0.1:8009/ClusterSample/ loadfactor=10 route=jvm1
       BalancerMember ajp://192.168.0.2:8009/ClusterSample/ loadfactor=10 route=jvm2
   </Proxy>

</IfModule>
</IfModule>

 stickysessionにJSESSIONIDを指定していますが、これはURLやcookie内のJSESSIONIDの後にピリオドを付加して、その後ろにrouteの文字列を付加することでサーバを割り振るための設定です。
 ここで注意すべきなのは、JSESSIONIDにrouteの文字列を付加するのはmod_proxy_balancerの仕事ではないということです。mod_proxy_balancerは文字列を読み取ってサーバを割り振ることだけしかしません。
 それではどのようにしてJSESSIONIDを加工するのでしょうか。実はTomcatにその設定があります。

1台目のserver.xmlに設定を追加します。
<!-- An Engine represents the entry point (within Catalina) that processes
    every request.  The Engine implementation for Tomcat stand alone
    analyzes the HTTP headers included with the request, and passes them
    on to the appropriate Host (virtual host). -->

<!-- You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Standalone" defaultHost="localhost" jvmRoute="jvm1">
    • >

<!-- Define the top level container in our container hierarchy -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">

 <!-- The request dumper valve dumps useful debugging information about
      the request headers and cookies that were received, and the response
      headers and cookies that were sent, for all requests received by
      this instance of Tomcat.  If you care only about requests to a
2台目のserver.xmlにも設定を追加します。
<!-- An Engine represents the entry point (within Catalina) that processes
    every request.  The Engine implementation for Tomcat stand alone
    analyzes the HTTP headers included with the request, and passes them
    on to the appropriate Host (virtual host). -->

<!-- You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Standalone" defaultHost="localhost" jvmRoute="jvm1">
    • >

<!-- Define the top level container in our container hierarchy -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm2">

 <!-- The request dumper valve dumps useful debugging information about
      the request headers and cookies that were received, and the response
      headers and cookies that were sent, for all requests received by
      this instance of Tomcat.  If you care only about requests to a

 これで、JSESSIONIDの後ろに.jvm1もしくは.jvm2といった文字列が付加されるようになります。
StickySessionの問題点

 StickySessionを利用する上で、困った問題があります。上記ではstickysession=JSESSIONIDのように設定していますが、文字列("JSESSIONID")の大文字小文字を区別してしまうのです。
 これがなぜ問題かというと、Tomcatでは普通、CookieにJSESSIONIDという名前の項目でセッションIDを保存します。しかし、Cookieが無効な場合URLにセッションIDを組み込むのですが、このときはjsessionidと小文字になってしまうのです。
 大文字のJSESSIONIDと小文字のjsessionid、両方に対応するような設定は現状では記述できませんので、どちらかをあきらめなければなりません。

※負け組SEの日常(http://makegumi.jp/blog/2007/06/mod_proxy_balancerstickysessio.html)様で、この問題に対応するパッチが公開されています。
最終更新:2011年01月13日 21:58
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。