Apache Software Foundation | Jakarta Project | Apache Tomcat
はじめに

Tomcatワーカは、 Webサーバの代わりにservletを実行するために待機しているTomcatインスタンスです。 たとえば、ApacheのようなWebサーバから、servletリクエストをバックグランドで動作しているTomcatプロセス (ワーカ) に転送することができます。

上の文は、非常に簡単な例について説明しています。 実際には、 特定のWebサーバのために、 複数のTomcatワーカがservletを処理するように設定することができます。 このような設定をおこなう理由は、以下の通りです。

  • すべての開発者が同じWebサーバを共有しながらも、自分専用のTomcatワーカを使用できる開発環境を提供するためには、 異なるTomcatワーカで異なるコンテキストを処理したいことがあります。
  • 異なる会社のサイトを明確に分離するために、 異なるバーチャルホストを異なるTomcatプロセスによって処理したいことがあ ります。
  • 負荷分散が必要になることがあります。 ここでいう負荷分散とは、複数のマシンに対して、それぞれTomcatワーカを実行しておき、リクエストをそれらに分散させることです。

複数のワーカを使用する理由はもっとあるでしょうが、とりあえずはこのリストでも充分でしょう。 Tomcatワーカはworkers.propertiesという名前のプロパティファイル中で定義しますが、このチュートリアルでは、それを設定する方法について説明します。

この文書はGal Shachorによって書かれた Tomcat-簡易ユーザーガイド の一部でしたが、文書構成の変更により、分離されました。


ワーカの定義

プロパティファイル (conf/ディレクトリ中のworkers.propertiesという名前のサンプルファイルが利用できます) を使用して、TomcatのWebサーバプラグインにワーカを定義することができます。

そのファイルは、以下のような形式のエントリを持っています。

worker.list =<コンマで区切られたワーカ名のリスト>

ワーカのリスト
worker.list= worker1, worker2

起動時には、Webサーバプラグインは、worker.listプロパティで指定された名前のワーカのインスタンスを作成します。これらのインスタンスは、リクエストの転送先のワーカでもあります。

ワーカタイプ

それぞれの名前のワーカは、 関連する他の情報を提供するために いくつかのエントリを持っています。 この情報は、ワーカのタイプや、他の関連したワーカの情報を含んでいます。 現在では、以下のようなワーカタイプが(JK 1.2.1には)存在します。

タイプ 解説
ajp12 このワーカは、ajpv12プロトコルを使ってリクエストをプロセス外 (out-of-process) Tomcatワーカに転送します。
ajp13 このワーカは、ajpv13プロトコルを使ってリクエストをプロセス外Tomcatワーカに転送します。
jni このワーカは、JNIを使ってリクエストをプロセス内 (inprocess) Tomcatワーカに転送します。
lb これは負荷分散 (load-balancing) ワーカです。ある程度の耐故障性を備えたラウンドロビンをベースにしたセッション維持型負荷分散 (sticky load balancing)ができます。

あるタイプのワーカを定義するためには、以下のようなプロパティフォーマットで設定します。

worker . ワーカ名 . type =<ワーカタイプ> ワーカ名の所には、ワーカに割り当てられた名前を、ワーカタイプの所には、上記の表で定義された4つのタイプのどれか一つを指定します (ワーカ名は、スペースを含むことはできません。この名前は、Java変数命名規則に従うのがよいでしょう、)。

ajpv12プロトコルを使ってリクエストをTomcatプロセスに転送する "local"という名前のワーカを定義しています。
worker.local.type=ajp12
ajpv13プロトコルを使ってリクエストをTomcatプロセスに転送する"remote"という名前のワーカを定義しています。
worker.remote.type=ajp13
jniを使ってリクエストをTomcatプロセスに転送する"fast"という名前のワーカを定義しています。
worker.fast.type=jni
負荷分散をおこなう"loadbalancer"という名前のワーカを定義しています。
worker.loadbalancer.type=lb



ワーカプロパティの設定

ワーカを定義するだけでなく、それらに対してプロパティを指定することができます。 プロパティは、以下のような形式で指定します。

worker.<ワーカ名>.<プロパティ>=<プロパティ値>

各ワーカは、以下のような分類ごとにプロパティの集合を持っていて、それらを指定することができます。

ajp12ワーカのプロパティ

ajp12というタイプのワーカは、TCP/IPソケット上でajpv12プロトコルを使用して、リクエストをプロセス外Tomcatワーカに転送します。

ajp12ワーカのプロパティは以下の通りです。

host プロパティはTomcatワーカが、ajp12リクエストを接続待ちしているホストを設定します。

port プロパティはTomcatワーカがajp12リクエストを接続待ちしているポートを設定します。

ワーカ名 "worker1" はマシン名www.x.comで待ち受けているTomcatに対し、8007番ポートにlb係数2.5で接続します。
worker.worker1.host=www.x.com
worker.worker1.port=8007
worker.worker1.lbfactor=2.5

註記: ajpv12プロトコルでは、一つのリクエストごとに、コネクションが作成され、使用され、閉じられます。 ajp12のデフォルトのポート番号は8007番です。


ajp13ワーカプロパティ

ajp13というタイプのワーカは、TCP/IPソケット上でajpv13プロトコルを使用して、リクエストをプロセス外Tomcatワーカに転送します。 ajpv12とajpv13の主な違いは以下の通りです。

  • ajpv13 は、よりバイナリ指向のプロトコルであり、頻繁に使用される文字列を小さな整数にコード化することで、リクエストデータを圧縮しようとします。
  • ajpv13 は、オープンしたソケットを再使用したり、後のリクエストのためにオープンしたままにします。 (WebサーバとTomcatの間にファイヤーウォールがある時に記憶させるなど)
  • ajpv13 は、コンテナがisSecure()のようなSSL関連のメソッドを実装できるように、 SSLの情報を特別扱いします。

Tomcat 4.0.x, 4.1.x, 5ではAjp13は現在、プロセス外プロトコルしかサポートされていないことを注意してください。

以下の表は、ajp13ワーカが受け付けることができるプロパティを列挙しています。

host プロパティはTomcatワーカが、ajp13リクエストを接続待ちしているホストを設定します。

port プロパティはTomcatワーカがajp13リクエストを接続待ちしているポートを設定します。

lbfactor プロパティは、負荷分散ワーカを使用している時の、ワーカの負荷分散係数です。詳しくは説明はlbワーカの章で説明します。

cachesize プロパティはワーカがオープンしておくソケット接続数を指定します。 デフォルトでは、この値は1です。 しかし、Apache 2.xx、IIS、NetscapeのようなマルチスレッドWebサーバでは、(Tomcatの平均的な並行ユーザ数を推測して)この値を増やした方が性能が向上するでしょう。

cache_timeout プロパティは、 JKがどれだけの間、開いたソケットを閉じられるまでキャッシュに保持しておくかを決めるために、 cachesize と共に使われます。 このプロパティは、Tomcat Web サーバのスレッドの数を縮小するために使われます。

重い負荷のかかったWebサーバ、たとえばApacheでは、 負荷を処理するためにたくさんの子プロセスやスレッドを作り、 負荷が下がったときには、その子プロセスやスレッドのみを破棄することを覚えておいてください。

それぞれの子プロセスはTomcatにリクエストを転送する必要があるとき、ajp13コネクションを開き、 新しいajp13スレッドをTomcat側に作成します。

ajp13コネクションが作成された後、子プロセスはkillされるまで、接続を切断しないという問題があります。 Web サーバは、子プロセス/スレッドが静的なコンテンツを処理していて、 Tomcat側で使用しないajp13スレッドを終了できる場合であっても、 高負荷状態を処理するために、子プロセス/スレッドを保持し続けます。

socket_keepalive プロパティは TomcatエンジンとWeb サーバの間にファイヤーウォールがあって、 使われない接続を切断したい場合に使用されます。 このフラグはオペレーティングシステムに対し、 不活性なコネクション(間隔はOSの設定により依存します。大概120分です) がKEEP_ALIVEメッセージを送るように伝えて、 ファイヤーウォールがコネクションを切断することを防止します。

ファイヤーウォールが使われない接続を切断するという問題は、 Web サーバとTomcatの双方が切断に関する情報を保持していなく、受け渡しできない ために起こります。

socket_timeout プロパティはWeb サーバに対し、 一定時間使われなかった場合、ajp13コネクションを切ることを指示します。 リクエストの終了が選択され、 割り当てられたソケットが開かれた時、 設定時間使用されなかったものが閉じられます。 これは、Tomcat側で古すぎるスレッドが存在しないよう、安全を確保するには良い方法です。 次回のリクエストを転送するために、ソケットを再び開くには余分なコストがかかります。 このプロパティは cache_timeout ととても似ています。 しかしnon-cache モードでも使用できます。

ワーカ "worker2" はwww2.x.comのポート8009のTomcatにlb係数3.5で接続します。
worker.worker2.host=www2.x.com
worker.worker2.port=8009
worker.worker2.lbfactor=3.5
ワーカ "worker2" は 最大10のソケットを使い、10分間以上キャッシュされないようにします。
worker.worker2.cachesize=10
worker.worker2.cache_timeout=600
ワーカ "worker2"はオペレーティングシステムに対し、 コネクションにKEEP-ALIVEシグナルを送ってもらうよう要求します。
worker.worker2.socket_keepalive=1
ワーカ "worker2" はajp13コネクションに5分後に接続を落とす(タイムアウトする)よう要求します。
worker.worker2.socket_timeout=300

注意: ajpv13プロトコルではデフォルトのポートは8009です。


lb ワーカプロパティ

負荷分散ワーカは、実際にTomcatワーカと通信することはありませんが、かわりにいくつかの"実際の"ワーカを管理します。 この管理は、以下の通りです。

  • Webサーバ内でワーカをインスタンス化します。
  • ワーカの負荷分散係数を使用して、重み付きラウンドロビン負荷分散を実行します。 高いlbfactorほど(多くのリクエストを処理できる)強いマシンです。
  • 同じセッションのリクエストは、同じTomcatワーカで実行するようにします。
  • ldワーカは、 ダウンしたTomcatワーカを検出して、それらにリクエストを転送するのを中断し、かわりに他のワーカに転送するように管理します。

この結果として、同じlbワーカが管理するワーカは(それらのlbfactorと現在のユーザのセッションを元に)負荷分散され、 一つのTomcatプロセスが死んでもサイト全体が"終了する"ことはないように、フォールバックします。

balanced_workers は負荷分散ワーカが管理しなければならない、コンマで区切ったワーカのリストです。 これらのワーカは、worker.listプロパティに記述してはいけません。

ワーカbalance1 は"real" ワーカとしてworker1とworker2を使用します。
worker.balance1.balanced_workers=worker1, worker2


拡張されたlbワーカのプロパティ

JK 1.2.xでは新しい負荷分散方式と耐故障性のサポートが、 local_worker_only local_worker の2つの新規プロパティにより 追加されました。

環境設定の例を見てみましょう。

それぞれのノードにWeb サーバとTomcatが並立して動作する2つのノード(worker1+worker2)を持つクラスタがあり、 ロードバランサがそのノードの前にある場合、

追加するrouter LB ワーカ
worker.list=router
# ajp13を使う'local_worker'ワーカを定義
worker.worker1.port=8009
worker.worker1.host=node1.domain.org
worker.worker1.type=ajp13
worker.worker1.lbfactor=1
worker.worker1.local_worker=1
# もう一つのajp13を使う'local_worker'ワーカを定義
worker.worker2.port=8009
worker.worker2.host=node2.domain.org
worker.worker2.type=ajp13
worker.worker2.lbfactor=1
worker.worker2.local_worker=0
# LB ワーカを定義
worker.router.type=lb
worker.router.balanced_workers=worker1,worker2
worker.router.local_worker_only=1

worker1とworker2の local_worker フラグは tells the lb_worker にどちらのワーカがローカルワーカなのかを伝えます。

local_workerが整数で0でない場合、JK_TRUEにセットされ、ローカルワーカと してマークがつけられます。 その他の場合、JK_FALSEとなります。 少なくとも1つのワーカがローカルワーカとしてマークされた場合、lb_workerはローカルワーカモードになります。 lb_workerが評価される間、すべてのローカルワーカは内部のワーカリスト先頭に移動されます。

このことは セッションIDを持つリクエストが入って来たとき、 適切なワーカに送られることを意味します。 もし、ワーカが落ちていたら、 エラー状態でない最初のローカルワーカに送られます。

セッションのないリクエストが来たとき、最初のローカルワーカに送られます。 すべてのローカルワーカがエラー状態にあるときは、 'local_worker_only'フラグは重要になります。 整数で、0でない場合、JK_TRUEにセットされ、その他の場合、JK_FALSEに なります。 JK_TRUEにセットされたとき、リクエストはエラーの応答を得ます。 JK_FALSEにセットされたとき、lb_workerは他の分散されたワーカにリクエス トを送ろうと試みます。

ワーカのうち一つがエラー状態になって、復旧した場合、何も変更されません。 ローカルワーカは、リクエストにセッションID付いていないか(と自身のセッションが付いているか)をチェックします。 その他のワーカは、そのワーカから来たセッションIDを持つリクエストかどうかだけがチェックされます。

何故このような複雑な振る舞いをしなくてはいけないのでしょう。 (訳注: 原文 souch は such の誤りでしょう。)

メンテナンスのためには、作法通りシャットダウンする必要があります。 フロントのバランサはそれぞれのノードの特別なポートに間をおいて依頼します。 ノードをクラスターから削除したいとき、そのポートを停止しなくてはなりません。 ロードバランサは接続できないとき、そのノードを落ちているとマークします。 しかし、セッションを他のノードに移すことができません。 この環境下では、バランサがセッション無しのリクエストを ポートが停止されているapache+mod_jk_tomcatに送った時、エラーになります。 そして、ロードバランサがノードが落ちていることを検出したとき、 他のノードへはセッションを持たないリクエストを送ることを許可されません 停止されたノード上の古いセッションのリクエストのみ、このノードに送られます。 以後しばらく、だれも古いセッションを使わなかった時、セッションはタイ ムアウトします。 そして、セッションが無くなり、セッションIDを持たないリクエストでノード が到達不能になるため、だれもこのノードを使わなくなります。 もし、だれかがタイムアウトしたセッションを使ったとき、 Servlet システムはセッションIDを持たないリダイレクトの応答をブラウ ザに返します。 このことは重要です。 なぜなら 停止されたノードでは、ApacheとTomcatは立ち上がって動作している必要があ るからです。 しかし、それらは古い状態にあるとき、古いセッションを検証するには尋ねられ るしかありません。 セッションを殺したり、他のノードに移さない場合、 最後のセッションがタイムアウトした後のみ、 ノードなどをアップデートすることができます。 巨大なオブジェクトがセッションの中に保持されているとき、それらを移すの に時間がかかることでしょう。

デフォルト値は現在、local_worker: 0 でlocal_worker_only:0です。


jniワーカプロパティ

jniワーカは、Webサーバプロセス内でJVMをオープンし、Tomcatを内部で(これはプロセス内です)実行します。 さらに、JNIメソッド呼び出しを使ってJVMとメッセージを交換しますので、 TCP/IPソケット上でAJPメッセージを使ってTomcatワーカと通信する必要があるプロセス外ワーカよりも高速です。

注意: JVMはマルチスレッド化されているので、jniワーカは、AOLサーバ、IIS、Netscape、Apache2.0のようなマルチスレッドサーバ内でしか使用できません。 さらに、Webサーバが使用しているスレッド機構がJK Webサーバプラグインを作成するために使用したものと一致するかどうかを確かめる必要があります。

jniワーカはJVMをオープンするので、クラスパスのようなJVMに転送する多くのプロパティを受け付けることができます。これを以下の表に示します。

class_path はプロセス内JVMで使用するクラスパスです。 これには、JVMのクラスパスに追加したいすべてのクラスファイルや jarファイルだけでなく、Tomcatのすべてのjar/クラスファイルを指定しなければいけません。

さらに、javacもクラスパスに追加するのを忘れないでください。 Java2では、これはtools.jarをクラスパスに追加することで可能です。 JDK 1.xxでは、単にclasses.zipをクラスパスに追加してください。

class_path プロパティは複数行にわたって指定できます。 この場合には、jk環境は、すべてのクラスパスのエントリの間にパスデリミタ(":"/";")を追加することで、クラスパスのエントリを連結して一緒にします。

ワーカのクラスパスを"wrkjni"にセットします
worker.wrkjni.class_path=/var/tomcat3/lib/tomcat.jar
JAVAC (tools.jar)を追加するのを忘れずに
worker.wrkjni.class_path=/opt/IBMJava2-131/lib/tools.jar

bridge はJNIを通じて使用するTomcatの種類を記します。

bridge プロパティは tomcat32 tomcat33 のためにあります。 Tomcat 3.2.x は推奨されません、しかし、iSeriesのようなディストリビュー ションが未だ存在します。 デフォルトではブリッジタイプはtomcat33にセットされています。

"wrkjni"のブリッジタイプを tomcat 3.3を使うように設定します。
worker.wrkjni.bridge=tomcat33

cmd_line はTomcatの起動コードに渡すコマンドラインです。

cmd_lineプロパティは複数行に渡って指定できます。 この場合には、jk環境はcmd_lineエントリの間に空白を挿入することで、cmd_lineエントリを連結して一緒にします。

"wrkjni"のコマンドラインを設定します。
worker.wrkjni.cmd_line=-config
次の引数
worker.wrkjni.cmd_line=/etc/tomcat3/conf/alt-server.xml
重要なtomcat.home
worker.wrkjni.cmd_line=-home
tomcat.homeのパス
worker.wrkjni.cmd_line=/var/tomcat3

jvm_lib はJVM実装ライブラリに対するフルパスです。 jniワーカは、このパスをJVMを動的にロードするために使用します。

JVM共有ライブラリへのパスを設定します。(IBM SDK on Linux)
worker.wrkjni.jvm_lib=/opt/IBMJava2-131/jre/bin/classic/libjvm.so
JVM共有ライブラリへのパスを設定します。(Sun SDK on Windows)
worker.wrkjni.jvm_lib=c:\JDK\1.3.1\jre\bin\classic

stdout はJVMがSystem.outを書き込むファイルへのフルパスです。

/var/log/http/jk-jvm-out.logにログを置きます。
worker.wrkjni.stdout=/var/log/http/jk-jvm-out.log

stderr はJVMがSystem.errを書き込むファイルへのフルパスです。

/var/log/http/jk-jvm-err.logにログを置きます。
worker.wrkjni.stderr=/var/log/http/jk-jvm-err.log

ms はJVMの初期ヒープサイズを設定します。

JVM に初期ヒープサイズとして 64MBを使うように指示します
worker.wrkjni.ms=64

mx はJVMの最大ヒープサイズを設定します。

JVMに128MB以上のヒープを使用しないように指示します。
worker.wrkjni.mx=128

sysprops はJVMにシステムプロパティを設定します。

JVMにフランス語を使用するように指示します。
worker.wrkjni.sysprops=-Duser.region=FR

ld_path は追加するダイナミックライブラリのパスです(LD_LIBRARY_PATHと同様です)。

システムにJava環境へアクセスするライブラリパスを追加するように指示します。
worker.wrkjni.ld_path=/opt/IBMJava2-131/jre/bin/
worker.wrkjni.ld_path=/opt/IBMJava2-131/jre/bin/classic

注意: Linux ではプロセスはそれ自身のLD_LIBRARY_PATHを追加できないようです。 そのため、Web サーバを立ち上げる前にアップデートする必要があります。


プロパティファイルのマクロ

Tomcatを起動する時に、プロパティファイル中で"マクロ"を定義することができます。 これらのマクロによって、プロパティを定義し、それを他のプロパティを記述するために使用できます。 たとえば、以下のようなコードを書くことができます。

プロパティ例。パス区切りをハードコードしない
workers.tomcat_home=d:\tomcat
workers.java_home=d:\sdk\jdk1.2.2
マクロを使って worker.inprocess.class_path=d:\tomcat\classes を定義
worker.inprocess.class_path=$(workers.tomcat_home)$(ps)classes
マクロを使って worker.inprocess.class_path=d:\sdk\jdk1.2.2\lib\tools.jar を定義
worker.inprocess.class_path=$(workers.java_home)$(ps)lib$(ps)tools.jar



サンプルのworker.properties

worker.propertiesを書き移すのは簡単ではないので、JKには、サンプルのworker.propertiesファイルがバンドルされています。

サンプルのworkers.propertiesには以下の定義が含まれています。

  • ホストがlocalhostでportが8007を使用するajp12ワーカ
  • ホストがlocalhostでportが8009を使用するajp13ワーカ
  • jniワーカ
  • ajp12とajp13ワーカに負荷分散するlbワーカ

# いくつかのプロパティを定義します。
workers.apache_log=/var/log/httpd/
workers.tomcat_home=/var/tomcat3
workers.java_home=/opt/IBMJava2-131/
ps=/
# 4つのワーカを定義します。3つのリアルワーカをajp12,ajp13,jniに、もう一つをロードバランス用ワーカに使います。
worker.list=worker1, worker2, worker3, worker4
# worker1のプロパティを設定します。(ajp12)
worker.worker1.type=ajp12
worker.worker1.host=locahost
worker.worker1.port=8007
worker.worker1.lbfactor=5
# worker2のプロパティを設定します。(ajp13)
worker.worker2.type=ajp13
worker.worker2.host=locahost
worker.worker2.port=8009
worker.worker2.lbfactor=50
worker.worker2.cachesize=10
worker.worker2.cache_timeout=600
worker.worker2.socket_keepalive=1
worker.worker2.socket_timeout=300
# worker3のプロパティを設定します。(jni)
worker.worker3.type=jni
# worker3のブリッジタイプをTomcat 3.3に設定します。
worker.worker3.bridge=tomcat33
# worker3のクラスパスを設定します。
worker.worker3.class_path=$(workers.tomcat_home)$(ps)classes
worker.worker3.class_path=$(workers.tomcat_home)$(ps)lib$(ps)tomcat.jar
# worker3 のTomcatのコマンドラインを設定します。
worker.worker3.cmd_line=-home
worker.worker3.cmd_line=$(workers.tomcat_home)
# worker3 のTomcatのJVMの設定をします。
worker.worker3.jvm_lib=$(workers.java_home)$(ps)jre$(ps)bin$(ps)classic$(ps)libjvm.so
worker.worker3.stdout=$(workers.apache_log)$(ps)inprocess.stdout
worker.worker3.stderr=$(workers.apache_log)$(ps)inprocess.stderr
worker.worker3.sysprops=tomcat.home=$(workers.tomcat_home)
# worker4 (lb)をworker1とworker2を使うように設定をします。
worker.worker4.balanced_workers=worker1,worker2


[訳注: これは新舘邦貴が翻訳しました。日本語訳に対するコメントがあれば、こちらに送って下さい。(風間一洋氏の翻訳を参考にしました。)]