トップ 一覧 検索 ヘルプ RSS ログイン

技術的雑談-複数のTomcatを立ち上げてmod_jk経由でロードバランスさせるの変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
!!!技術的雑談-複数のTomcatを立ち上げてmod_jk経由でロードバランスさせる

!!環境
*使用OS:CentOS 3.5
*httpd:Apache 2.0.46(多分2.0.xだったら大丈夫)
*JDK 1.5.0_10
*Apache tomcat 5.5.17
*mod_jk(tomcat-connector) 1.2.20

*[[mod_jkを使ってTomcatとhttpdを連携する|技術的雑談-mod_jkを使ってTomcatとhttpdを連携する]]が完了していること。

!!目的
*1つのサーバ(OSインスタンス)上で複数のTomcatインスタンスを立ち上げる。
*mod_jkの機能を使い、複数のTomcat(JSP/Servletエンジン)を1つのhttpdから公開する。

今回の完成版の構成図は以下のようになります。

                  ┌――――┐
 httpリクエスト→ │ Apache ├―――┐ 処理を依頼 ┌――――┐
                  |        |mod_jk|―――――→| Tomcat1|
 httpレスポンス← |        |      |←―――――|        |
                  |        |      | 結果を返す └――――┘
                  |        |      |
                  |        |      | 処理を依頼 ┌――――┐
                  |        |      |―――――→| Tomcat2|
                  |        |      |←―――――|        |
                  |        |      | 結果を返す └――――┘
                  └――――┴―――┘    ※ 2つのTomcatは同一OSインスタンス上で稼動

例えば、
「どうしてもあるWeb ApplicationでTomcatインスタンスを1つ占領したい」
「Tomcatの処理能力を増やしたい」
「実験をしたい!」(ぉ
などの目的に使用できます。

また、別記の[[複数のTomcat間でSessionの途切れないClusterを作る|技術的雑談-複数のTomcat間でSessionの途切れないClusterを作る]]の基礎技術にもなります。

!!手順

!Tomcatの複数インスタンスとは?

普通、Tomcatは1つのJava-VM上でマルチスレッド動作をし、複数のWeb Applicationを単一のTomcatで処理する事ができます。
server.xmlを読むとわかるのですが、Tomcatのインスタンス(メモリー上で実行されている実体)1つの中にも複数のEngineを定義したり、ContextというWeb Applicationの単位を追加したりできます。
(この辺の話は…そのうち書くかもしれない。とりあえず外部参照!(爆))

ただ、試験や特別の理由でサーバ1台(≒OSインスタンス1つ。最近はXenとかVMWareとかあるのでハード的なサーバ1台=OS1つではなくなってきつつある…(汗))に複数台のTomcatを乗せて動かしてみたりしたくなることもあります。

ここでは単純に、
「startup.shを叩いて起動されるTomcatのプロセス一つ=Tomcat 1つ」と考えます。

しかし、TomcatはディレクトリやSocketなど諸々のOSリソースを占有するServerなので、単純に「startup.sh」を2回叩いてもTomcatは2つにはなりません。(後から起動したTomcatがエラーになり立ち上がらないはずです。)

!Tomcatが使用するリソース

現状、Tomcatが使用するCPUとHDDとMemory以外のリソースは以下のもののようです。
(いずれもDefaultのserver.xmlの状態で。)

::TCP Socket 8005番
:::TomcatのShutdownなどのコマンドを投入する為に使われています。
::TCP Socket 8009番
:::Tomcatがmod_jkと通信する為に使用されます。(全くDefaultのserver.xmlではコメントアウトされているかもしれません。)
::TCP Socket 8080番
:::TomcatがHTTPプロトコルを受け付けるために使用されます。
::(Tomcatの元Directoryの)/temp/ Directory
:::TomcatのSessionなどの情報がShutdown時に一時記憶されたりするらしいです。
::(Tomcatの元Directoryの)/work/ Directory
:::JSPが一時的にコンパイルされたり、Session情報が入れられたりします。
:::server.xmlの<Engine>タグのname要素で指定されたEngine名前でサブDirectoryが作られ、その下にWeb Application名でDirectoryが作られ、その下にファイルが置かれます。
::(Tomcatの元Directoryの)/log/ Directory
:::Tomcat実行時のLogファイルが作成されます。
::(Tomcatの元Directoryの)/conf/ Directory
:::Tomcatの設定ファイルが置かれます。
::(Tomcatの元Directoryの)/webapp/ Directory
:::Tomcatで処理されるWeb ApplicationのJSPやServletが置かれます。

!準備

今回、「複数のTomcatを1つのhttpdで束ねる」という全体なので、mod_jkが既にInstallされて稼動可能になっていないとなりません。

!Install

/usr/java/apache-tomcat-5.5 Directoryを同じOS内でコピーします。
ここでは仮に/usr/java/apache-tomcat-5.5-2とします。

!設定

まず、apache-tomcat-5.5-2側のserver.xml内のTCP Portをapache-tomcat-5.5とぶつからないように修正します。

::<Server port="8005" shutdown="SHUTDOWN">
:::この"8005"を空いているTCP Port番号にします。(ここでは9005にします。)
::<Connector port="8009" enableLookups="false" protocol="AJP/1.3" />
:::この8009を空いているTCP Port番号にします。(ここでは9009にします。)
::<Engine name="Catalina" defaultHost="localhost">
:::念のため、ここのname="Catalina"を"Catalina2"にします。これによってwork/下の内容がwork/Catalina2/に作られるようになります。

次に、これはapache-tomcat-5.5側でもapache-tomcat-5.5-2側でも行わなくてはならないのですが、それぞれのEngineにmod_jkの振り分けに使う名前を付けます。

これは何かと言うと、Tomcat上でのSession情報とTomcatインスタンスの齟齬が起きないようにする為のものです。

例を挙げると、

+Clientがhttpdにリクエストを投げる
+httpdはそれがJSP/Servletが処理するべきものだと判断したらそれをmod_jkに回す
+mod_jkはTomcat1にそのリクエストを処理させたとする。この時、Tomcat1ではSession ID「AAAA」を発行するとする。
+処理結果をmod_jk経由でhttpd→Clientに返す。ClientはSession ID 「AAAA」を今回のSessionと信じる。
+ClientがSession 「AAAA」の次のリクエストとしてまたhttpdに要求を投げる。
+httpdはそれがJSP/Servletが処理するべきものだと判断したらそれをmod_jkに回す
+mod_jkは(振り分け方法が指定されていなかったら)負荷分散のために今度はTomcat2に処理を回す。
+Tomcat2はSession ID 「AAAA」なるものは知らないので、Session ID 「AAAA」を無効とし、新しいSession ID 「BBBB」を発行する。
+処理結果をmod_jk経由でhttpd→Clientに返す。ClientはSession ID 「BBBB」を今回のSessionと信じる。
+以下繰り返し。

つまり、Session IDがリクエストの度に発行され、Sessionの意味がなくなってしまう。

これを防ぐには、一旦作成されたSessionを、Sessionを発行したTomcatで処理し続ければよい。
(※違ったアプローチで「Session IDと内容を共有する」という方法も当然ある。それが別記のTomcat Cluster化のこと。)

TomcatのEngineに対してmod_jk用の振り分け名を付けるには、server.xmlの<Engine>タグに「jvmRoute」というPropertyを追加する。

 # apache-tomcat-5.5側のserver.xml
 <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
 
 # apache-tomcat-5.5-2側のserver.xml
 <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">

この時のjvmRouteの文字列は後でworkers.propertiesにも記載するので覚えておく。

次に、workers.propertiesファイルを編集する。

 worker.list=wlb, jkstatus
 
 # tomcat1(apache-tomcat-5.5)用の設定
 worker.tomcat1.port=8009
 worker.tomcat1.host=localhost
 worker.tomcat1.type=ajp13
 
 # tomcat2(apache-tomcat-5.5-2)用の設定
 worker.tomcat2.port=9009
 worker.tomcat2.host=localhost
 worker.tomcat2.type=ajp13
 
 # 割り振り比率の設定(ここでは両Tomcatに均等になるようにリクエストを分散する)
 worker.tomcat1.lbfactor=10
 worker.tomcat2.lbfactor=10
 
 # ロードバランサーの設定
 worker.wlb.type=lb
 worker.wlb.balance_workers=tomcat1, tomcat2
 worker.wlb.sticky_session=True
 worker.wlb.method=Session

::実worker名
:::実worker名は'''必ず'''jvmRouteの名前とあわせる。そうしないと正常にSessionが振り分けられない。
:::文献によっては「任意の値でOK」みたいに書かれているが、「jvmRouteにあわせる」が正解。(確認済み。)
::worker.list
:::後述するロードバランサーの仮想workerを含める。逆にtomcat1などの実workerは含めてはいけない。
::port、localhost、type
:::それぞれTomcatの実際の設定に沿った定義をする
::lbfactor
:::小さいほうがより多くの仕事を振られる。同じロードバランサーに所属する実Workerのlbfactor値は相対的に比較され、比率が決定される。
::worker.wlb.type=lb
:::「type=lb」はロードバランサーを意味する特別なworker種類
::balance_workers
:::このロードバランサーの振り分け対象となる実Workerをカンマ区切りで列挙する。
::sticky_session
:::Sessionごとに使用するTomcatを固定する、という意味。(書かなくても=TrueがDefaultらしいが…。)
::method=Session
:::振り分け単位を設定する。他にはRequest、Trafficなどの設定があるらしいけど試してない。何も指定しないとRequestが指定されたことになるらしい。

最後にhttpd.conf、又はmod_jk.confを修正し、worker「wlb」でJSP/Servletの処理を行うように指定する。

 	JkMount		/jsp-examples/*	wlb
 	JkMount		/jkstatus	jkstatus

!起動・終了

前記の設定を終えたら両Tomcat、httpdを再起動する。
エラーが出なければひとまずOK。

!確認

下記のような.jspファイルを作り、配置する。

 <%@ page language="java" %>
 <html>
 	<body>
 		<h1><font color="red">Session Servered by Tomcat</font></h1>
 		<table align="center" border="1">
 			<tr>
 				<td>Session ID</td>
 				<td><%= session.getId() %></td>
 			</tr>
 			<tr>
 				<td>Created on</td>
 				<td><%= session.getCreationTime() %></td>
 			</tr>
 		</table>
 	</body>
 </html>

単にSession IDと作成時刻を表示するだけの簡単なJSPです。

これを
/usr/java/apache-tomcat-5.5/webapps/jsp-examples/

/usr/java/apache-tomcat-5.5-2/webapps/jsp-examples/
にindex2.jspという名前で作成する。

(Tomcat、httpdを再起動しなくてもアクセス可能になるはず。)

ブラウザで「http://〜/jsp-examples/index2.jsp」にアクセスする。
この時、表示されるSession IDが(SessionのTimeout以内の間隔で)ブラウザからページをリロードしても変わらなければ成功。
もしSession IDがコロコロ変わるようだったらjvmRouteとworker名の関係がずれている。

次に、ブラウザで「http://〜/jkstatus」を開いて、mod_jkの稼動状況を表示させる。

まずでっかく、
「Listing Load Balancing Worker (1 Worker)」と表示されていない時はworkers.propertiesの設定が間違っているか、workers.propertiesの修正後にhttpdを再起動していない。

次にその下の部分に、ロードバランサー配下の実WorkerのStstusが表示されている。

 Balancer Members [Hide]
        Name    Type  Host           Addr           Act Stat D F  M V Acc Err CE Wr   Rd  Busy Max Route    RR Cd Rs 
 [E|R]  tomcat1 ajp13 localhost:8009 127.0.0.1:8009 ACT N/A  0 10 1 0 81  0   0  23K  56K 0    2   tomcat1        0
 [E|R]  tomcat2 ajp13 localhost:9009 127.0.0.1:9009 ACT N/A  0 10 1 0 25  0   0  7.6K 14K 0    1   tomcat2        0

ここではまず両方Workerが「ACT」であること。
これが「ERR」とかなっている場合はそちらのTomcatが起動していないか、server.xmlとworkers.propertiesのPort番号がずれていることが考えられる。

次に、先程のindex2.jspを何度か叩いてみたあとで、jkstatusの画面をリロードする。
Session IDが変わっていなくて、かつ片方の「Acc」だけが増えているのが正解。
(ちゃんとSticky Sessionが機能している。)

これが両方増えてしまう時は、誰か他にアクセスしている人がいるか、Sticky Sessionが効いていないかのどちらか。
後者の場合は
*両server.xmlのjvmRouteがちゃんとユニークであること。
*server.xmlのjvmRouteとworkers.propertiesのworker名が同じになっていること。
*jvmRouteとTomcatのPortがちゃんと正しく(テレコになったりせずに)対応している事。
を確認する事。

!ちなみに

言うまでもない事ですが、Tomcatを別々のOSインスタンスや別サーバに立ち上げ、そのサーバのIPアドレスをworkers.propertiesでlocalhostの代わりに指定すれば、(本当の意味での)ロードバランシングされたJSP/Servletエンジンになります。
!!関連項目

*[[LinuxでのJDKのInstall|技術的雑談-LinuxでのJDKのInstall]]

*[[Tomcat5.5をLinuxにInstallする|技術的雑談-Tomcat5.5をLinuxにInstallする]]

*[[mod_jkを使ってTomcatとhttpdを連携する|技術的雑談-mod_jkを使ってTomcatとhttpdを連携する]]

*[[複数のTomcat間でSessionの途切れないClusterを作る|技術的雑談-複数のTomcat間でSessionの途切れないClusterを作る]]

!!履歴
2007/01/18 -- 初版

[[技術的雑談]]へ戻る

!!突っ込み
{{comment}}

[[技術的雑談]]へ戻る

{{trackback}}

[[技術的雑談]]へ戻る