- 追加された行はこのように表示されます。
- 削除された行は
このように表示されます。
!!!技術的雑談-複数の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}}
[[技術的雑談]]へ戻る