PHPに限らず、Webアプリケーションを動かしているとどこかのタイミングでHTTPサーバを再起動する必要に迫られることがあります。
そのタイミングで誰もアクセスしていないという保証があるのなら話は簡単なのですが、その保証があることは、以前は極めて稀でした。近年では再起動すべきタイミングにおいては稼働中のサーバを一旦ロードバランサーから切り離すことで新規の HTTP Request を受け付けないようにし、実行中の処理が全て捌けてから再起動するといった運用も行われます。とは言え、再起動したときにどのような現象が起きるのかを知っておくことは無駄ではありません。何故なら、1秒を争うような状況に追い込まれてしまったときはロードバランサーの操作をせずに再起動することも考えられるからです。他にも知っておくと幸せになれる場面はあるでしょう。
このあたりの挙動に関して、自分の知識がn年前の状態のまま更新されていないことに気付いたので、ちょっと実験することにしました。
HTTPサーバ経由で実行された PHP のプログラムが、HTTPサーバ再起動(やそれに近い操作)によってどのように取り扱われるのか。試してみましょう。
PHP の処理
次のようなものを用意しました。それぞれの処理が実行されている途中で、再起動(など)を実施します。
wait_with_sleeping.php
: sleep関数で処理に時間がかかる場合wait_consuming_cpu_resource.php
: PHPの処理でCPU資源を食い潰している場合wait_on_background.php
: PHPのコードの中からバックグラウンドプロセスを立ち上げた場合
コードは GIST として公開しています。
PHPで時間のかかる処理を再現する。signalとか受け取ったときの挙動の確認。 · GitHub
検証結果
再起動方法 | sleep | CPU資源を食う処理 | バックグラウンド |
---|---|---|---|
sudo service httpd restart |
死ぬ | 死ぬ | 死ぬ |
sudo service httpd reload |
死ぬ | 死ぬ | 死ぬ |
sudo service httpd graceful |
sleepが中断される | きちんと待ってくれる | 死なない |
sudo service nginx restart |
死ぬ | 死ぬ | 死なない |
sudo service nginx reload |
きちんと待ってくれる | きちんと待ってくれる | 死なない |
ちなみに、PHP 5.6 でも同様の結果が得られました。
標準で用意されているサービス取り扱いのコマンドの範囲では、NGINX の方がより直感的な運用ができるかもしれません。signalを受け取ったら sleep
がinterruptされる挙動を期待するようなプログラムを書いているのであれば Apache の方が良いでしょう。もっとも、この特性以外の要因の方が、HTTPサーバを選択する上で重要である場面は多いでしょう。
そう言えば以前、Apacheで運用しているサービスで sudo service httpd reload
を流したところバックグラウンドの処理が死んでしまってビビったことがあるのを思い出しました。今だから言える。