トップ 差分 一覧 ソース 検索 ヘルプ 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


 目的

  • 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の複数インスタンスとは?


普通、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インスタンスの齟齬が起きないようにする為のものです。

例を挙げると、

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

つまり、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エンジンになります。

 関連項目






 履歴

2007/01/18 -- 初版

技術的雑談へ戻る

 突っ込み

name   comment  
URL (入力するとす ぱ むとみなします!)


技術的雑談へ戻る

TrackBack

TrackBack URL for this entry:
http://www.himajin2001.com/fswiki/tb.cgi/%B5%BB%BD%D1%C5%AA%BB%A8%C3%CC%2D%CA%A3%BF%F4%A4%CETomcat%A4%F2%CE%A9%A4%C1%BE%E5%A4%B2%A4%C6mod%5Fjk%B7%D0%CD%B3%A4%C7%A5%ED%A1%BC%A5%C9%A5%D0%A5%E9%A5%F3%A5%B9%A4%B5%A4%BB%A4%EB

技術的雑談へ戻る

最終更新日時:最終更新時間:2007年01月18日 09時36分35秒
トップページに戻る