!!!技術的雑談-複数の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のタグの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とぶつからないように修正します。 :: :::この"8005"を空いているTCP Port番号にします。(ここでは9005にします。) :: :::この8009を空いているTCP Port番号にします。(ここでは9009にします。) :: :::念のため、ここの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のタグに「jvmRoute」というPropertyを追加する。 # apache-tomcat-5.5側のserver.xml # apache-tomcat-5.5-2側のserver.xml この時の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" %>

Session Servered by Tomcat

Session ID <%= session.getId() %>
Created on <%= session.getCreationTime() %>
単に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}} [[技術的雑談]]へ戻る