Apache HTTP Server の停止と再起動

この文書では Unix に類似したシステムでの Apache HTTP Serverの停止と再起動について扱っています。 Windows NT, 2000, XP ユーザはサービスとして httpd を実行するで、Windows 9x, MEユーザはコンソールアプリケーションとして httpd を実行するで、 これらのプラットホームでの使用方法をご覧下さい。

httpd apachectl Starting
イントロダクション

Apache HTTP Server を停止したり再起動したりするためには、実行されている httpd プロセスにシグナルを送る必要があります。 シグナルを送るには二つの方法があります。 一つ目はプロセスに直接シグナルを送る unix の kill コマンドを使用する方法です。 システムを見ればたくさんの httpd が 実行されているのに気が付くでしょうが、シグナルを送るのは 親プロセスだけで、それ以外の個々のプロセスには シグナルを送らないで下さい。その親プロセスの pid は PidFile に書かれています。これはつまり、親以外のプロセスに シグナルを送る必要すらない、ということです。 親プロセスに送ることができる 4 種類のシグナルがあります: TERM, HUP, USR1, WINCH です。これらの説明については続きをご覧下さい。

親プロセスにシグナルを送るには、 次のようなコマンドを発行して下さい:

kill -TERM `cat /usr/local/apache2/logs/httpd.pid`

httpd プロセスにシグナルを送る 2 番目の方法は -k というコマンドライン引数を使用することです。 下で説明されているように、stop, restart, graceful, graceful-stop を指定できます。 これらは httpd の引数ですが、 制御用のスクリプト apachectl はそれらの引数をそのまま httpd に渡します。

httpd にシグナルを送った後、 実行状況を次のコマンドで読むことができます:

tail -f /usr/local/apache2/logs/error_log

ここに挙げた例は、各自の ServerRootPidFile の設定に適合するように適宜修正して下さい。

急な停止
シグナル: TERM
apachectl -k stop

TERM あるいは stop シグナルを親プロセスに送ると、即座に子プロセス全てを kill しようとします。 子プロセスを完全に kill し終わるまでに数秒かかるかもしれません。 その後、親プロセス自身が終了します。 処理中のリクエストは全て停止され、もはやリクエストに対する 応答はされません。

緩やかな再起動
シグナル: USR1
apachectl -k graceful

親プロセスは USR1 あるいは graceful シグナルを受け取ると、子プロセスに現在のリクエストの処理の後に終了する (あるいは何もしていなければすぐに終了する) ように助言します。 親プロセスは設定ファイルを再読込して、ログファイルを開き直します。 子プロセスが徐々になくなるに従って、 新しい世代の設定による子プロセスに置き換えていきます。 そして、これらが新たなリクエストに即座に応答し始めます。

このコードは常に MPM のプロセス制御ディレクティブの設定を重視しますので、 クライアントのリクエストを扱うプロセスとスレッドの数を再起動の処理中も 適切な値に維持されます。。また、次のようにして StartServers を守ります: 少なくとも 1 秒後に StartServers 個の新しい子プロセスが 生成されていなければ、その数になるように適宜プロセスを生成します。 この挙動は現在の負荷に対して適切な子プロセスの数と StartServers パラメータでの 希望の数の両方を維持しようとしています。

mod_status を 使用している場合は、USR1 シグナルが送られた際に サーバ統計がゼロに設定されないことに 注意してください。 サーバが新しいリクエストに応答不能な時間を最小にするように (リクエストは OS によってキューに追加されるので絶対に紛失はしません)、 また同時に、希望のチューニングパラメータを守るように コードは書かれています。 このようにするために、世代をまたがった全子プロセスの追跡に使われている スコアボードを維持しなければなりません。

status モジュールは、緩やかな再起動以前から開始して リクエストに応答し続けている子プロセスを特定するために、 G を使うこともします。

現在、USR1 を使うログ移動スクリプトでは、 再起動前の子プロセスがログを書き終わったことを確証する方法が ありません。古いログに対して何かする前に、 USR1 シグナルを送った後いくらか適当な時間待つことを 提案します。例えば、帯域の狭い通信路のユーザのリクエストのほとんどが 10 分以下で完了しているということが分かっていれば、 古いログに何かする前に 15 分待つということです。

再起動が発行されると設定ファイルの構文チェックがまず走り、 設定ファイルに (構文上の) 誤りがないかチェックされます。 誤りがあった場合エラーメッセージでその旨が示され、サーバは再起動されません。 こうすることでサーバが終了しているけれども再起動できないという状況を 防ぎ、サーバが機能不全な状態になるのを防いでいます。

ただしこれでもサーバが正しく再起動することは保証されません。 設定ファイルの意味的な内容を構文と同様に検証したい場合は、 非 root ユーザで httpd を起動しようとすればわかります。 もしエラーがなければ、ソケットやログを開こうとして root でないため (もしくは実行中の httpd が既に必要なポートにバインドしているため) に失敗するでしょう。 これ以外の理由で起動に失敗したのであれば、 それは設定ファイルのエラーで、 緩やかな再起動を行う前にその誤りを修正しなければなりません。

急な再起動
シグナル: HUP
apachectl -k restart

HUP あるいは restart シグナルを親プロセスに送ると、 TERM と同様に子プロセスを kill しますが、 親プロセスは終了しません。 設定ファイルを再読込して、ログファイル全てを開き直します。 その後、新しい子プロセスを起動して応答を続けます。

mod_status を使っている場合は、HUP が送られた場合に サーバ統計がゼロに設定されることに注意してください。

graceful 再起動時は、再起動前に構文チェックが行われます。 もし構文エラーがあればその旨が示され、再起動は行われません。
緩やかな停止
Signal: WINCH
apachectl -k graceful-stop

WINCHgraceful-stop シグナルを受け取ると、 親プロセスは子プロセスに現在処理中のリクエストの後に終了する (あるいは処理中のものが何もなければ直ちに終了する) ようにアドバイスします。 その後親プロセスは PidFile を削除し、ポートでの Listen を全て停止します。 親プロセスはどの子プロセスがリクエスト処理中かを監視し続けています。 全ての子プロセスが終了するか GracefulShutdownTimeout で設定した時間が過ぎると、親プロセスも終了します。 タイムアウトに達した場合、残りの子プロセスには TERM シグナルが送信され強制的に終了されます。

"graceful" 状態の場合 TERM シグナルを受け取ると、 親プロセスも子プロセスもすぐに終了します。しかしながら PidFile が削除されてしまっているので、apachectlhttpd にこのシグナルを送ることはできません。

graceful-stop を使うとまったく同一に設定された 複数の httpd を同時に実行することができます。 httpd を緩やかにアップグレードするのにはとても便利ですが、 設定ファイルによってはデッドロックやレースコンディションを 引き起こすこともあります。

ディスク上のファイルを使うもの、たとえばロックファイル (Mutex) や Unix ソケットファイル (ScriptSock) などはサーバの PID を含めて管理されていて、 共存できるよう注意が払われています。 しかしその他設定ディレクティブやサードパーティ製のモジュール、 CGI ユーティリティのパーシステント層などで ディスク上にロックファイルや状態管理ファイルを 使っている場合は、実行されている複数の httpd が互いに衝突しないように気をつけなければなりません。

rotatelogs 形式のパイプを使ったログといった、 その他潜在的なレースコンディションについても注意しなければなりません。 複数の rotatelogs が同じファイルを同時に rotate しようとすると、互いにログファイルを破壊してしまいます。