Links User Guide Reference Apache Tomcat Development | | クイック・スタート |
Tomcat 5.5 コンテナでセッション・レプリケーションを走らせるには,次のステップを完遂します:
- セッション・アトリビュートはすべて
java.io.Serializableを実装する必要があります。
- server.xml の
Cluster エレメントのコメントアウトを解除します。
- server.xml の
Valve(ReplicationValve) エレメントのコメントアウトを解除します。
- 同一マシンで複数の Tomcat インスタンスを走らせるときは,
tcpListenPort アトリビュートが各インスタンスで一意的になるようにします。
web.xml に <distributable/> を設けるか,
<Context distributable="true" /> でセットします。
[訳注: web.xml については Sun の Servlet 2.3 仕様書を参照。Context エレメントについては
context.html を参照。ただし,後者に distributable の記述はない]
- Engine に jvmRoute アトリビュートをセットします。
<Engine name="Catalina" jvmRoute="node01" >
[訳注: Engine エレメントについては engine.html を参照]
- すべてのノードが同じ時刻を持ち,NTP サービスで同期されていること!
- ロードバランサが sticky session mode に設定されていることを確認します。
ロード・バランシングは
Load Balancing の章に見るように多くの技術で達成できます。
注意: セッション・ステートはクッキーによってトラックされます。
ですから,外から見たとき URL が同じに見えなくてはなりません。
そうしないと新しいセッションが作られることになります。
クラスタリング・サポートは現在,JDK バージョン 1.4 以降を必要とします。
|
| 動作方法 |
どのようにクラスタが動作するのか理解しやすくするために,私たちはあなたを一連のシナリオに案内します。
このシナリオでは私たちは二つの tomcat インスタンス TomcatA と TomcatB
だけを使うことにします。下記のシーケンスのイベントをカバーします。
TomcatA が起動する
TomcatB が起動する (TomcatA が起動し終わるのを待つ)
TomcatA がリクエストを受け取る。セッション S1 が作られる
TomcatA がクラッシュする
TomcatB がセッション S1 のリクエストを受け取る
TomcatA が起動する
TomcatA がリクエストを受け取る。セッション (S1) の無効化が求められる
(invalidate is called on the session (S1))
TomcatB が新しいセッション (S2) のリクエストを受け取る
TomcatA セッション S2 が放置により (due to inactivity) 無効化される
Ok, さてこのシーケンスで,正確には何がセッション・レプリケーション・コードに起こっているのか,あなたを案内しましょう。
TomcatA が起動する
Tomcat が標準的な起動シーケンスでスタートします。
Host オブジェクトが生成されたとき,cluster オブジェクトがそれに関連づけられます。
各 context をパースするとき,もしも distributable エレメントが web.xml の代わりにあれば,
Tomcat は Cluster クラス (この場合 SimpleTcpCluster) に対し,
レプリケートされた context のマネージャを生成するように頼みます。
web.xml に distributable をセットしてクラスタリングをイネーブルにしたときも同様です
[訳注: 原文は英語文法として破格。ここではピリオド等を補って訳した]。
Tomcat は StandardManager のかわりにその context に対し
DeltaManager を生成します。
cluster クラスは membership サービス (マルチキャスト) とレプリケーション・サービス
(tcp ユニキャスト) を起動します。
アーキテクチャの詳細についてはこのドキュメントのずっと後で [説明します]。
TomcatB が起動する
TomcatB が起動するときは,ひとつの例外を除いて TomcatA と同じシーケンスをたどります。
クラスタがスタートし, membership (TomcatA, TomcatB) が確立されます。
それから TomcatB はクラスタの既存サーバ (この場合 TomcatA) に対し,そのセッション・ステートをリクエストします。
TomcatA はリクエストに応答し,TomcatB が
HTTP リクエストでの待ち受けを始める前に,ステートが TomcatA から TomcatB へ転送されます。
TomcatA が応答しない場合, TomcatB は 60 秒後にタイム・アウトし,log エントリを発行します。
web.xml に distributable を持っている各 web アプリケーションに対し,それぞれセッション・ステートが転送されます。
注: セッション・レプリケーションを効率的に使うには,あなたの tomcat
インスタンスをすべて同じようにコンフィグすべきです。
TomcatA がリクエストを受け取る。セッション S1 が作られる
TomcatA に到来するリクエストは,セッション・レプリケーション無しのときと正確に同様に扱われます。
アクションはリクエストの完了時に起こります。
レスポンスがユーザへ返される前に ReplicationValve
がリクエスト [訳注: レスポンスの誤り?] を横取ります[訳注: この2文の原文は comma fault で文意不明瞭]。
この時点でそれはセッションが変更されていることを発見し,TCP を使ってセッションを TomcatB
に replacata [ママ] します。
直列化されたデータをオペレーティング・システムの TCP ロジックに渡してしまった後,valve
パイプラインを通じてリクエスト [レスポンス?] がユーザに戻されます。
リクエストごとにセッション全体がレプリケートされますから,レプリケートされるべきセッションのアトリビュートを
setAttribute や removeAttribute を呼ばずに変更できます。
セッションがレプリケートされる回数を最適化するために,
コンフィグレーション・パラメタ useDirtyFlag を使うことができます。
TomcatA がクラッシュする
TomcatA がクラッシュする時,TomcatB は TomcatA がクラスタから脱落したという知らせを受け取ります。
TomcatB は TomcatA を membership リストから外します。
TomcatA はこれ以降 TomcatB に起きたいかなる変化も知らされなくなります。
ロード・バランサは TomcatA から TomcatB へリクエストをリダイレクトするはずです。
セッションはすべて継続します。
TomcatB がセッション S1 のリクエストを受け取る
エキサイティングなことは何もありません。
TomcatB はリクエストを他のどんなリクエストとも同じように処理します。
TomcatA が起動する
起動する時, TomcatA は,新しいリクエストを受け取って自分自身を利用可能にする前に
上記 1) 2) に記述された起動シーケンスをたどります。
クラスタに加入し,すべてのセッションの現在のステートについて TomcatB にコンタクトします。
セッション・ステートを受け取ったら,ローディングを終了して HTTP/mod_jk ポートを開きます。
ですから TomcatB からセッション・ステートを受け取ってしまうまでは TomcatA でリクエストは処理されません。
TomcatA がリクエストを受け取り, セッション (S1) の無効化が求められる
(invalidate is called on the session (S1))
呼出しが [TomcatB に] 横取りされたことは,無効化の理由になります
[訳注: 原文は "The invalidate is call is intercepted"
--動詞 invalidate をドイツ語のように自由に名詞として使っているのだろうか?]。
セッションが,[他の] 無効化されたセッションと一緒にキューに入れられます。
リクエストの完了時,変更されたセッションを送出するかわりに "期限切れ"
メッセージを TomcatB へ送出し,TomcatB も同様にセッションを無効化します。
TomcatB が新しいセッション (S2) のためのリクエストを受け取る
ステップ 3) と同じシナリオです。
TomcatA セッション S2 が放置 [訳注: 原文では "inactivity" (不活発さ)。
ユーザが Web ページを表示したまま放置したという意味か?] により無効化される
セッションは,ユーザにより無効化されたときも,呼出しが横取りされた場合と同じように無効化されます
[訳注: 原文は意味不明瞭。訳文は推測による仮訳。
"The invalidate is call is intercepted the same was as when a session is invalidated by the user"]。
セッションは,[他の] 無効化されたセッションと一緒にキューに入れられます。
この時点では invalidet [ママ] セッションは,他のリクエストがシステムから
到来して無効化キューをチェクするまでレプリケートされません
[訳注: 無効化されたセッションがレプリケートされるはずはなく意味不明瞭だが,
単に放置されているだけでは "期限切れ" メッセージは送出されず,
ほかにリクエストがあったときについでに処分される,という意味か?]。
ふーっ! (Phuuuhh!) :)
Membership
クラスタリングの membership は非常に簡単なマルチキャスト ping を使って確立されます。
各 Tomcat インスタンスは定期的にマルチキャスト ping を送出します。
ping メッセージでインスタンスはその IP とレプリケーション用 TCP listen ポートをブロードキャストします。
所定の時間枠内にインスタンスがこのような ping を受け取らなかったならば,
そのメンバは死んだと見なされます。
とても単純ですが,とても効果的です!
もちろん,あなたはシステムのマルチキャスティングを有効にしておく必要があります。
[訳注: 実際には,いわゆる ping コマンドと異なり,ICMP ではなく,java.net.MulticastSocket による UDP
を通信に利用している]
TCP レプリケーション
いったんマルチキャスト ping が受け取られると,メンバがクラスタに追加されます。
次回のレプリケーション・リクエストでは,送出側のインスタンスはそのホストとポート番号の情報を使って
TCP ソケットを確立します。
このソケットを使って直列化データを送出します。
私が TCP ソケットを選んだ理由は,それがフロー制御と到達保証性を組込んでいるからです。
だから,私が何かデータを送った時,それは送り先に届くと分かるわけです :)
分散ロッキングとフレームを使ったページ
Tomcat はクラスタ間で同期的にセッション・インスタンスを保持するわけではありません。
そのようなロジックは多くのオーバーヘッドを生み,あらゆる種類の問題を引き起こすでしょう。
もしもクライアントが複数のリクエストを使って同じセッションに同時にアクセスしたならば,
最後のリクエストがクラスタ内の他のセッション [のレプリカ] を上書きすることになります。
|
| Cluster コンフィグレーション |
cluster コンフィグレーションはサンプルの server.xml ファイルで説明されています。
注意すべき点として, mcastXXX で始まるアトリビュートは membership multicast ping
用で, tcpXXX で始まるアトリビュートは実際の TCP レプリケーション用だということです。
membership は全 tomcat インスタンスにより確立されます。
全 tomcat インスタンスは同じ multicast IP アドレスとポート番号でブロードキャスト・メッセージ
を送ります [訳注: 原文は英語として破格。
"The membership is established by all the tomcat instances are sending broadcast messages
on the same multicast IP and port"
--おそらく are を省くか,are の前に which を補うべき]。
TCP listen port は,セッション・レプリケーションを他のメンバから受け取るポートである。
replication valve は,リクエストが完了した時を見つけて,レプリケーションを始めるために使われます。
性能について最も重要な考慮事項のひとつは,レプリケーションの (プール化または非プール化) 同期モード 対 非同期モードです。
同期レプリケーション・モードでは,レプリケートされたセッションが
LAN ケーブルを越えて伝送され他の全クラスタ・ノードで再実体化されるまで,リクエストは返されません。
同期レプリケーションには二つの設定があります。プール化 (pooled) と非プール化です。
非プール化設定 (つまり replicationMode="fastasnycqueue" または "synchronous")
ではすべてのレプリケーション・リクエストが単一のソケットで伝送されます。
同期モードの使用は,多量のメッセージが生成されるときボトルネックになりかねません。
replicationMode="pooled" にセットすることで,このボトルネックを克服できますが,
今度は worker スレッドがレプリケーションでブロックされます。
ここでの推奨方法は,到来するレプリケーション・リクエストを処理するスレッドの数を増やすことです。
これが server.xml の cluster セクションの tcpThreadCount プロパティです。
プール化設定は,複数のソケットを使って性能を向上させることを意味します。
非同期レプリケーションは,sticky session を fail over するまで維持するときに使うとよいでしょう。
このときは,データのレプリケーションにかかる時間ではなく,リクエストにかかる時間が重要になります。
このとき tcpThreadCount を ノード数 - 1 にします。
非同期レプリケーションをしているときは,データがレプリケートされる前にリクエストが返されます。
非同期レプリケーションはより短いリクエスト時間をもたらします。
その一方,同期レプリケーションは,リクエストが返される前にセッションがレプリケートされることを保証します。
パラメタ "replicationMode" には4とおりの設定があるわけです: "pooled", "synchronous", "asynchronous" そして "fastasyncqueue"
|
| JMX によるクラスタのモニタリング |
モニタリングは,あなたがクラスタを使う時の非常に重要な問題です。
クラスタ・オブジェクトのいくつかは JMX MBean です。
Java 5 [ならば] 起動スクリプトに下記のパラメタを追加します。
 |  |  |  |
set CATALINA_OPTS=\
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=%my.jmx.port% \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false
|  |  |  |  |
JDK 1.4 で JMX をアクティベートする [には]:
- compat パッケージをインストールします。
- mx4j-tools.jar を common/lib にインストールします (tomcat のリリースと同じバージョンの mx4j を使います)。
- MX4J JMX HTTP Adaptor をあなたの AJP Connector に設定します
 |  |  |  |
<Connector port="${AJP.PORT}"
handler.list="mx"
mx.enabled="true"
mx.httpHost="${JMX.HOST}"
mx.httpPort="${JMX.PORT}"
protocol="AJP/1.3" />
|  |  |  |  |
- tomcat をスタートさせ,ブラウザで http://${JMX.HOST}:${JMX.PORT} を見ます。
- connector パラメタ
mx.authMode="basic" mx.authUser="tomcat" mx.authPassword="strange"
でアクセスを制御できます!
List of Cluster Mbeans
| Name |
Description |
MBean ObjectName - Engine |
MBean ObjectName - Host |
| Cluster |
The complete cluster element |
type=Cluster |
type=Cluster,host=${HOST} |
| ClusterSender |
Configuration and stats of the sender infrastructure |
type=ClusterSender |
type=ClusterSender,host=${HOST} |
| ClusterReceiver |
Configuration and stats of the recevier infrastructure |
type=ClusterReceiver |
type=ClusterReceiver,host=${HOST} |
| ClusterMembership |
Configuration and stats of the membership infrastructure |
type=ClusterMembership |
type=ClusterMembership,host=${HOST} |
| IDataSender |
For every cluster member it exist a sender mbeans.
It exists speziall MBeans to all replication modes |
type=IDataSender,
senderAddress=${MEMBER.SENDER.IP},
senderPort=${MEMBER.SENDER.PORT} |
type=IDataSender,host=${HOST},
senderAddress=${MEMBER.SENDER.IP},
senderPort=${MEMBER.SENDER.PORT} |
| DeltaManager |
This manager control the sessions and handle session replication |
type=Manager,path=${APP.CONTEXT.PATH}, host=${HOST} |
type=Manager,path=${APP.CONTEXT.PATH}, host=${HOST} |
| ReplicationValve |
This valve control the replication to the backup nodes |
type=Valve,name=ReplicationValve |
type=Valve,name=ReplicationValve,host=${HOST} |
| JvmRouteBinderValve |
This is a cluster fallback valve to change the Session ID to the current tomcat jvmroute. |
type=Valve,name=JvmRouteBinderValve,
path=${APP.CONTEXT.PATH} |
type=Valve,name=JvmRouteBinderValve,host=${HOST},
path=${APP.CONTEXT.PATH} |
|
|