サーバーをチューニングする前に、Web Server の接続処理プロセスを理解しておくべきです。この節では、次の内容について説明します。
Web Server では、待機ソケット上のアクセプタスレッドが接続を受け付け、それらを接続キューに入れます。次に、スレッドプール内の要求処理スレッドがキューから接続を取り出し、その要求を処理します。
また、別のスレッドプールに要求を送信して処理を依頼するように、要求処理スレッドに指示することもできます。たとえば、要求処理スレッドがスレッドに対して安全でないある作業を実行する必要がある場合、その処理の一部を NativePool に送信するように指示することができます。NativePool は作業が完了すると、その結果を要求処理スレッドに伝え、要求処理スレッドが要求の処理を続行します。
サーバーの起動時に作成されるのは、スレッドプールの最小スレッド数に定義された数のスレッドだけであり、これはデフォルトで 16 個です。負荷が増えるとサーバーによって追加のスレッドが作成されます。新しいスレッドの追加ポリシーは、接続キューの状態に基づいています。
新しい接続が返されるたびに、キュー内で待機している接続の数 (接続のバックログ) が、すでに作成された要求処理スレッドの数と比較されます。待機している接続の数がスレッド数を上回った場合、次回の要求完了時に新しいスレッドが追加されるようにスケジュールされます。
新しいセッションスレッドの追加プロセスは、最大スレッド数の値に厳密に制限されます。最大スレッド数の詳細については、「最大スレッド数 (最大同時要求数)」を参照してください。
スレッド、プロセス、および接続の数やタイムアウトに影響を与える設定を変更するには、管理コンソールで、構成の「パフォーマンス」タブ (HTTP 設定) および「HTTP リスナー」タブを使用します。また、wadm コマンド set-thread-pool-prop、set-http-listener-prop、および set-keep-alive-prop を使用することもできます。
サーバーは、負荷に応じて 2 つのモードのいずれかで稼働できます。負荷の増減にもっとも効率的に対応できるようにモードを切り替えます。
高並行性モードでは、要求の処理が完了すると、セッションスレッドがその接続をキープアライブサブシステムに渡す。高並行性モードでは、キープアライブサブシステムがすべてのキープアライブ接続に対して新しい要求のポーリングを行う。
サーバーの起動時には、短待ち時間モードが使用されます。負荷が増えると、サーバーは高並行性モードに移行します。短待ち時間モードから高並行性モードに移行したり、元の短待ち時間モードに戻ったりする判断は、接続キューの長さ、平均セッション合計数、平均アイドルセッション数、および現在のアクティブセッション数とアイドルセッション数に基づいて、サーバーによって行われます。
スレッドプールが無効化されると、スレッドがプール内に作成されず、接続キューやキープアライブスレッドも作成されません。スレッドプールが無効になると、アクセプタスレッド自身が要求を処理します。
前述した設定に加え、magnus.conf ファイル内で次の指令を編集すれば、NSAPI プラグイン向けの要求処理を追加で構成できます。
KernelThreads – カーネルによってスケジュールされたスレッド上で NSAPI プラグインを常に実行するかどうかを決定します (Windows のみ)
TerminateTimeout – サーバーの停止時に、NSAPI プラグインが要求の処理を完了するのをサーバーが最大でどれだけの時間待つかを決定します
これらの指令の詳細については、『Sun Java System Web Server 7.0 Administrator’s Configuration File Reference』を参照してください。
magnus.conf などの構成ファイルを編集するためのもっとも安全な方法は、wadm コマンド get-config-file と set-config-file を使って編集用のローカルコピーを取得し、それを Web Server に戻すことです。これらのコマンドの詳細については、各コマンドのヘルプを参照してください。
デフォルトでは、接続キューはデフォルトのスレッドプールに要求を送信します。ただし、magnus.conf 内でスレッドプールの Init 関数を使ってユーザー独自のスレッドプールを作成することもできます。これらのカスタムスレッドプールは、要求の全体を処理するためではなく、NSAPI サービスアプリケーション関数 (SAF) を実行するために使用されます。
SAF がカスタムスレッドプールの使用を必要とする場合、現在の要求処理スレッドは、要求をキューに入れ、カスタムスレッドプール内の別のスレッドがその SAF を完了するまで待機したあと、その要求の残りの部分を完了します。
たとえば、obj.conf ファイルの内容が次のようになっているとします。
NameTrans fn="assign-name" from="/testmod" name="testmod" pool="my-custom-pool" ... <Object name="testmod"> ObjectType fn="force-type" type="magnus-internal/testmod" Service method=(GET|HEAD|POST) type="magnus-internal/testmod" fn="testmod_service" pool="my-custom-pool2" </Object>
この例の場合、要求は次のように処理されます。
要求処理スレッド (この例では A1 と呼ぶ) が要求を取り出し、NameTrans 指令の前の手順を実行します。
URI が /testmod で始まっている場合、A1 スレッドはその要求を my-custom-pool キューに入れます。A1 スレッドは待機します。
my-custom-pool 内の別のスレッドをこの例では B1 スレッドと呼びますが、A1 によってキューに入れられた要求をその B1 が取り出します。B1 がこの要求の処理を完了し、待機段階に戻ります。
A1 スレッドが呼び起こされ、その要求の処理を続行します。これは、ObjectType SAF を実行したあと、Service 関数に移ります。
この Service 関数は my-custom-pool2 内のスレッドによって処理される必要があるため、A1 スレッドが要求を my-custom-pool2 キューに入れます。
my-custom-pool2 内の別のスレッドをこの例では C1 と呼びますが、キューに入れられた要求をその C1 が取り出します。C1 がこの要求の処理を完了し、待機段階に戻ります。
A1 スレッドが呼び起こされ、その要求の処理を続行します。
この例では、3 つのスレッド A1、B1、および C1 が動作して要求の処理を完了させます。
追加のスレッドプールは、スレッドに対して安全でないプラグインを実行するための手段の 1 つです。最大スレッド数が 1 に設定されたプールを定義すると、指定されたサービス関数内で 1 つの要求しか実行できなくなります。前述の例で testmod_service がスレッドに対して安全でない場合には、そのサービスを単一のスレッドを使って実行する必要があります。my-custom-pool2 内に単一のスレッドを作成すれば、この SAF がマルチスレッド化された Web Server 内で正常に動作するようになります。
スレッドプールの定義方法の詳細については、『Sun Java System Web Server 7.0 Administrator’s Configuration File Reference』の「thread-pool-init」を参照してください。
Windows 上では、実行にネイティブスレッドを必要とする NSAPI 関数を実行する目的で、ネイティブスレッドプール (NativePool) がサーバーによって内部的に使用されます。
Web Server は NSPR (Netscape Portable Runtime) を使用します。これは移植性を高めるための基盤層であり、ホスト OS のサービスへのアクセス機能を提供します。この層はスレッドの抽象化を提供しますが、それは必ずしも、OS が提供するスレッドに対する抽象化と同一であるとは限りません。これらの非ネイティブスレッドのスケジューリングオーバーヘッドは比較的低いので、それらを使用すればパフォーマンスを改善できます。ただし、これらのスレッドは、入出力呼び出しなど、OS に対するブロック呼び出しの影響を受けやすい性質を持っています。ブロック呼び出しを使用する可能性のある NSAPI 拡張の記述を容易にするために、サーバーはブロック呼び出しを安全にサポートするスレッドのプールを保持します。これらのスレッドは通常、ネイティブ OS スレッドになります。要求の処理中に、非ネイティブスレッド上で安全に実行できる関数としてマークされていない NSAPI 関数はすべて、ネイティブスレッドプール内のいずれかのスレッド上で実行されるようにスケジュールされます。
ユーザーが NameTrans、Service、PathCheck 関数など、独自の NSAPI プラグインを記述した場合、それらの関数はデフォルトで、ネイティブスレッドプール内のスレッド上で実行されます。プラグインが NSAPI 関数を入出力のためだけに使用しているか、あるいは NSAPI 入出力関数をまったく使用していない場合、そのプラグインは非ネイティブスレッド上で実行できます。そのためには、その関数の読み込み時に NativeThread="no" オプションを指定し、ネイティブスレッドを必要としないことを示す必要があります。
たとえば、magnus.conf ファイル内の load-modules Init 行に、次のコードを追加します。
Init funcs="pcheck_uri_clean_fixed_init" shlib="C:/Sun/webserver7/lib/custom.dll" fn="load-modules" NativeThread="no"
NativeThread フラグは funcs リスト内のすべての関数に影響を与えます。したがって、ライブラリ内に関数が 2 つ以上存在しているが、ネイティブスレッドを使用するのはその一部だけである場合には、複数の Init 行を使用してください。NativeThread を yes に設定すると、スレッドは直接 OS スレッドにマップされます。
load-modules 関数については、『Sun Java System Web Server 7.0 Administrator’s Configuration File Reference』の「load-modules」を参照してください。
マルチプロセスモードは非推奨です。したがって、次の各節の情報は、下位互換性を維持するためだけに含まれています。マルチプロセスモードが非推奨になっているのは、今日では大部分のアプリケーションがマルチスレッド化されており、マルチプロセスモードは通常、必要とされないからです。
Sun Java System Web Server は、次の 2 つのモードのいずれかで実行できます。
シングルプロセスモードでは、サーバーは Web クライアントからの要求を単一のプロセスを使って受信します。単一サーバープロセスの内側ではアクセプタスレッドが実行されており、新しい要求が到着するのを待っています。要求が到着すると、アクセプタスレッドが接続を受け付け、その要求を接続キューに入れます。要求処理スレッドが接続キューから要求を取り出し、その要求を処理します。
サーバーはマルチスレッド化されているため、サーバー用に記述された NSAPI 拡張はすべて、スレッドに対して安全でなければいけません。つまり、NSAPI 拡張がファイルへの共有参照やグローバル変数など、あるグローバルリソースを使用している場合には、一度に 1 つのスレッドしかそのリソースにアクセスしないように、そのリソースの使用を同期させる必要があります。Web Server に付属するプラグインはすべて、スレッドに対して安全であり、かつスレッドを認識するため、高いスケーラビリティーと並行性を実現できます。これに対し、旧バージョンのアプリケーションはシングルスレッドである可能性があります。サーバーがそうしたアプリケーションを実行する場合、一度に 1 つしか実行できません。このため、高負荷下ではサーバーパフォーマンスの問題が発生します。残念ながら、シングルプロセスの設計では、現実的な回避方法は存在しません。
複数のプロセスと各プロセス内の複数のスレッドを使って要求を処理するように、サーバーを構成することができます。この柔軟性により、スレッドを使用するサイトで最適なパフォーマンスを実現できるだけでなく、スレッド化された環境内で実行する準備が整っていない旧バージョンのアプリケーションを実行するサイトで、下位互換性を維持することができます。Windows 上のアプリケーションは一般に、すでにマルチスレッドを活用しているため、この機能は UNIX および Linux プラットフォームに適用されます。
マルチプロセスの利点は、スレッドを認識しないかスレッドに対して安全でない旧バージョンのアプリケーションを、Sun Java System Web Server 内でより効果的に実行できるという点です。ただし、Sun Java System 拡張はどれもシングルプロセスのスレッド化環境をサポートするように構築されているため、それらの拡張がマルチプロセスモードでは動作しない可能性があります。サーバーがマルチプロセスモードになっていると検索プラグインの起動が失敗し、セッションレプリケーションが有効になっていると、マルチプロセスモードでのサーバーの起動が失敗します。
マルチプロセスモードの場合、サーバーは起動時に、複数のサーバープロセスを生成します。各プロセスには、受信要求を受け取るためのスレッドが、構成に応じて 1 つ以上含まれます。各プロセスは完全に独立しているため、グローバル変数、キャッシュ、およびその他のリソースの独自のコピーを持ちます。複数のプロセスを使用する場合、多くのリソースがシステムに必要です。また、共有状態を必要とするアプリケーションのインストールを試みる場合、そのアプリケーションは複数のプロセス間でその状態の同期を取る必要があります。NSAPI には、プロセス間の同期を実装するためのヘルパー機能は用意されていません。
MaxProcs 値として 1 より大きい値を指定すると、サーバーは、複数のサーバープロセス間で接続を分散する処理をオペレーティングシステムに依頼します (MaxProcs 指令については「MaxProcs (UNIX/Linux)」を参照)。ただし、最近のオペレーティングシステムの多くは、同時接続数が少ない場合は特に、接続を均等に分散しません。
Sun Java System Web Server はサーバープロセス間での均等な負荷分散を保証できないため、スレッドに対して安全でない旧バージョンのアプリケーションに対応するために「最大スレッド数」を 1 に、MaxProcs を 1 より大きい値にそれぞれ設定すると、パフォーマンスの問題が発生する可能性があります。旧バージョンのアプリケーションにバックエンドデータベースが含まれている場合など、旧バージョンのアプリケーションが要求に応答するまでに長い時間がかかる場合には特に、この問題が顕著になります。このシナリオではおそらく、「最大スレッド数」にデフォルト値を使用し、旧バージョンのアプリケーションへのアクセスをスレッドプールを使って直列化するのが適切です。スレッドプールの作成方法の詳細については、『Sun Java System Web Server 7.0 Administrator’s Configuration File Reference』の「thread-pool-init」を参照してください。
サーバー内で NSAPI を 1 つも実行しない場合には、次のデフォルト設定を使用するべきです。1 つのプロセスと多数のスレッド。スレッド化された環境内でのスケーラビリティーを持たないアプリケーションを実行する場合には、少数のプロセスと多数のスレッド、具体的には 4 個または 8 個のプロセスと、1 プロセスあたり 128 個または 512 個のスレッドなどを使用するべきです。
MaxProcs は非推奨であり、下位互換性を維持するためだけに含まれています。
UNIX/Linux サーバーをマルチプロセスモードに設定するには、この指令を使用します。このモードを使えば、マルチプロセッサマシン上でのスケーラビリティーが向上する可能性があります。これを 1 より小さい値に設定すると、その値は無視され、デフォルト値の 1 が使用されます。
MaxProcs の値を設定するには、magnus.conf 内の MaxProcs パラメータを編集します。
サーバーを MaxProcs モードで実行すると、起動メッセージが重複して表示されます。