Servlet BOF (1999/5/19)
Apache JServのWebサーバ・Servletエンジン間通信モデル
風間 一洋
E-mail: kazama@ingrid.org
日本電信電話(株) 未来ねっと研究所
概要
Apache JServのWebサーバとServletエンジン間の通信モデルを,
特に1.0b4の負荷分散機能に重点を置いて解説する.
1. mod_jservモジュール
- mod_jservは,
mod_cgi,
mod_perl,
mod_phpなどのモジュールと異なり,
パーザやインタープリタを含まない
- 特定のServletエンジンに依存しない
- AJPをサポートしたServletエンジンを使用できる
- マルチプロトコル化も考えられる
- mod_jservの役目
- Servletエンジンの起動 (オートスタートが設定されている場合)
- HTTPリクエストからAJPリクエストに変換し,Servletエンジンに送信する
- ServletエンジンからAJPレスポンスを受信し,HTTPレスポンスに変換する
- 設定ファイル
- Webサーバ側の設定…httpd.conf
- Servletエンジン側の設定…jserv.properties + 各ゾーン用プロパティファイル (例, zone.properties)
2. ローカルモードとリモートモード
2.1 ローカルモード
- たいていのServletエンジンはローカルモードに相当する
- WebサーバとServletエンジンが同一マシン上で動作する
- 同じシステムリソース(例, CPU, ディスク, メモリ)を共有する
- WebサーバとServletエンジン間の通信速度
- ループバックインタフェースを使用するので高速 (Sun Exterprise 450/10Base-Tでは転送速度は約6倍)
- servletの実行速度
- Servletエンジンの自動起動ができる
設定例
ローカルゾーン"/root"を,
Webサーバの"/servlets"にマウントする.
ApJServMount /servlets /root
2.2 リモートモード
- ServletエンジンがWebサーバとは異なるマシン上で動作し,TCP/IPで通信する
- WebサーバとServletエンジンが異なるシステムリソースを使用できる
- Webサーバとは異なる,
特定のマシンにしかないリソースを使用したい場合には,
リモートモードを使わなければならない
- WebサーバとServletエンジン間の通信速度
- ループバックインタフェースより低速
- 物理ネットワークの転送速度やトラフィックの影響を受ける
- servletの実行速度
- Servletエンジンは自動起動できない
設定例
手動で起動するように設定し,
リモートのゾーン"/root"を,
Webサーバの"/servlet"にマウントする.
ApJServManual on
ApJServMount /servlets ajpv11://192.168.0.51:7777/root
注意
セキュリティへの配慮が必要になる
- 運用に使用するネットワークをsecureに管理する
- アドレスフィルタリング
- 認証
- Servletエンジンをfirewallの内側に置く
- ユーザID, グループIDの管理
- chrootコマンドの使用
3. 通信プロトコル
- AJP = Apache JServ Protocol
- 現在のAJP 1.1は,AJP 1.0をリモートモードで認証できるように改良したプロトコル
- 認証,リクエスト,レスポンスの3種類に分類できる
- 認証
- MD5を使用している (暗号としては解きやすいが,輸出規制がない)
- AJP 1.1では認証はリクエストごとに実行されるので効率が悪い(1)
- AJP 2.1ではKeep Alive接続に変更されるので,
コネクションが張られる時だけ認証がおこなわれる(2)
- リクエスト
- サーバ名
- 環境変数
- HTTPリクエストのヘッダ
- リクエスト・エンティティ
- シグナル
- レスポンス
- ステータス
- Servletエラー
- レスポンス・エンティティ
4. 接続形態
WebサーバとServletエンジンの基本的な接続形態は,以下のように分類される.
さらに目的に応じて,
基本パターンを柔軟に組み合わせた多対多接続がおこなえる.
- 一対一接続
- 多対一接続
- Servletエンジンを共有する
- Webサーバの方が負荷が高い
- 一対多接続
- 異なる実行環境 (JDK, JRE)を同時に使用する
- JDK, JREのバージョン
- オプション
- クラスパス
- 実行環境を分割して処理能力や安定性を向上させる
- 大規模プログラムを動作させる
- 一対多接続(ラウンドロビン)
- 負荷分散による処理能力を向上させる
- watchdog機能を併用することで,耐障害性を確保する
5. 処理性能の確保
アクセス頻度やWebサーバ・Servletエンジンの負荷に応じて,
WebサーバとServletエンジンの処理性能を独立に,
複数のレベルの対処ができる.
- 複数のServletエンジン(同一マシン)に静的負荷分散
- 異なるservletプログラムを異なる環境で実行する
- 同期などのオーバーヘッドが減少する
- 複数のServletエンジン(別マシン)に静的負荷分散
- 異なるservletプログラムを別のマシンで実行する
- 異なるシステムリソースを使用する
- 複数のServletエンジンに動的負荷分散
- 同一のservletプログラムを複数のマシンで実行する
- 複数のマシンで並列に処理できる
- 動作するservletは制限される
マルチプロセッサマシン(+ネイティブスレッドVM)はより効果的である
- servletプログラムはマルチスレッドプログラムであり,
並列に実行できる
- servletプログラムの種類に制限がない
- ローカルモードで実行すれば,
通信オーバヘッドが少なくできる
- ハードウェアやOSが限定される
- 高価
- プロセッサ数と単位あたりのリクエスト処理時間には,次のような相関関係がある(図1).
- 並列実行リクエスト数がプロセッサ数以下の場合には,
ほぼ一定時間で処理することができる.
ただし,Webサーバを同じマシン上で動作させる場合には,
若干の影響を受ける.
- 並列実行リクエスト数を越えた場合には,
リクエスト処理時間の上昇度合いが低く,平均時間は1CPUあたりの時間の"1/プロセッサ数".
ただしservletプログラムに,
スレッドの並列実行を生かすように記述されていない場合には,
この限りではない.
図1. プロセッサ数とリクエスト処理時間の相関関係
注意点
- servletの実行時間(Servletエンジン単体)ではなく,
HTTPリクエストが発行されてからレスポンスを受け取るまでのトータルの時間を(WebサーバとServletエンジンのシステムとして)評価しなければならない
- 並行実行リクエスト数を変化させて評価しなければならない
(servletが実行速度と,servletの並行)
6. 負荷分散
- DNSを利用したラウンドロビン
- WebサーバとServletエンジンの関係が固定される
- mod_rewriteモジュールを使用する手法(3)
- 1.0b3以前に使用されていた
- セッション管理が使えない
- watchdog機能がない (各自作成する必要がある)
- Apache JServの負荷分散機能(4)
7. 負荷分散可能なservlet
- 状態を持たないservlet…○
- セッション単位で状態を保持するservlet…○
- メモリ上にない共有リソース(共有ファイル,データベース)を使って情報を共有するservlet…○
- 共有変数を読み書きするservlet…×
8. 負荷分散のために追加された機能
- httpd.confのbalanceパラメタ
- セッション処理
- 共有メモリ (1.0b4以降)
- watchdogプロセス (1.0b4以降)
9. balanceパラメタ
httpd.confの設定例
# Apache JServをマニュアル起動にする
ApJServManual on
# /servletを負荷分散する
ApJServMount /servlet balance://set1/zone1
# マシンのウェイトを設定する
ApJServBalance set1 PC
ApJServBalance set1 SPARC4 # 4CPU
# Servletエンジンを指定する
ApJServHost PC ajpv11://192.168.0.51:7777
ApJServHost SPARC ajpv11://192.168.0.52:8888
# ここで定義した名前をセッションcookieの末尾に付加する
ApJServRoute JS1 PC
ApJServRoute JS2 SPARC
# 共有メモリファイルを設定する
ApJServShmFile logs/jserv_shm
注意
- あまり大きいウェイト値は使用しない
- Apache JServ Status Handlerは対応していないので,状態が正しく表示されない
- http://localhost/jserv/にアクセスすると,mod_jservモジュールやServletエンジンの状態や設定を見ることができる
10. セッション処理
- 一旦セッションを確立した後は,同じJServにリクエストを割り当てる
- セッションcookieと,ApJServRouteパラメタを比較して判断する.
- 負荷分散した場合には,
ApJServRouteで指定した名前がセッションIDの末尾に付加される
- セッションIDの例: 3fecc6170d56b05e.1.927035618945.JS1
- HTTPサーバをDNSでラウンドロビンする場合には,同じApJServRouteパラメタを使用しなければならない.
注意
プログラムで直接cookieを操作せずに,
Servlet APIのセッション管理を使用しなければ,
セッションを正しく維持できない.
11. 共有メモリ
- httpdプロセス間の通信に使用される.
- ディスク上のファイルをread/writeでmmapすることにより実現する(MT-safe, MP-safeではない / 排他制御されない).
- 他のプログラム(CGI, SNMPプロキシ,inetdが管理するサーバ)からアクセスして,モニタ・管理できる(jserv.hで構造体が定義 / jserv_mmap.cが例).
- 現在の制限は25 (jserv.hのNB_MAX_JSERVで定義)
12. watchdogプロセス
- watchdogプロセスは,
Servletエンジンの状態を監視するプロセスである
- Apacheの起動時に,watchdogプロセスは,通常のHTTPリクエストを受付け
ないhttpdプロセスとして起動される
- 10秒間隔で各Servletエンジンの状態を観測し,共有メモリに記録する
- Servletエンジンの状態
- UP…JServが動作中
- DOWN…JServが返答しない
- SHUTDOWN_IMMEDIATE…管理者がJServを停止し,リクエストを受付けない.
- SHUTDOWN_GRACEFUL…管理者がJServを停止したが,
すでにあるセッションのリクエストは許可される
(例, 10秒後に停止する)
注意
1.0b4のNT版ではwatchdogプロセスは実装されていない
13. watchdogアルゴリズム
while true
do
10秒sleepする.
if このプロセスが(共有メモリ中で)デフォルトwatchdogではない?
break
endif
for 共有メモリ中のリストの各Jserv
do
if JServ.state = DOWN
JServに接続
if 接続に失敗?
continue
else
共有メモリに"UP"とマークする
endif
endif
done
done
14. 負荷分散アルゴリズム
for 負荷分散servletマウントポイントに来た各HTTPリクエスト
do
if そのマウントポイントに対する最初のHTTPリクエストか?
then
process_mount_default_target = ターゲットの組からランダムに選択
endif
if セッションcookieが存在するか?
then
セッションを持っているJServを検索(ApJServRouteパラメタを使用)
if そのJServが共有メモリで"UP"または"SHUTDOWN_GRACEFUL"か?
then
JServにリクエストを送信
if リプライが存在するか?
then
return
else
JServが(共有メモリに)"DOWN"とマークする
endif
endif
endif
# ここで,セッションcookieが存在しない,またはセッションが壊れてい
# るリクエストを受け取った処理をおこなう.後者の場合には,クライア
# ントに相談せずに,リスト中の別のターゲットにリクエストを送信でき
# る(ただし,セッションが壊れていることを通知する必要はあるかもしれない).
if process_target != process_mount_default_target AND
process_mount_default_targetが共有メモリで"UP"か?
then
process_target = process_mount_default_target
endif
while (process_targetが存在する?)
do
if process_targetが共有メモリで"UP"か?
then
JServにリクエストを送信する
if リプライが存在するか?
then
return
else
JServを(共有メモリ中で)"DOWN"にマークする
endif
endif
process_target = 次のターゲット
done
done
参考資料
- The Java Apache Project:
"Apache JServ Protocol Version 1.1 (AJPv1.1)",
http://java.apache.org/jserv/protocol/AJPv11.html,
1998.
- The Java Apache Project:
"Apache JServ Protocol Version 2.1 (AJPv2.1)",
http://java.apache.org/jserv/protocol/AJPv21.html,
1998.
- The Java Apache Project:
"Frequently Asked Questions",
http://java.apache.org/jserv/FAQ.html#load_balancing,
v. 1.15,
1999.
- The Java Apache Project:
"How to : Scalability - Load-Balancing - Fault tolerance with
Apache JServ 1.0b4 and higher",
http://java.apache.org/jserv/howto.load-balancing.html,
1999.
- Stefano Mazzocchi & Pierpaolo Fumagalli:
"Servlet Performance and Apache JServ",
http://java.apache.org/jserv/papers/performance.pdf,
ApacheCon '98,
1998.
- Stefano Mazzocchi & Pierpaolo Fumagalli:
"Advanced Apache JServ Techniques",
http://java.apache.org/jserv/papers/techniques.pdf,
ApacheCon '98,
1998.
(風間 一洋 NTT未来ねっと研究所)