読者です 読者をやめる 読者になる 読者になる

職業プログラマの休日出勤

職業プログラマによる日曜自宅プログラミングや思考実験の成果たち。リアル休日出勤が発生すると更新が滞りがちになる。記事の内容は個人の意見であり、所属している(いた)組織の意見ではない。

PHP処理中にHTTPサーバ再起動

PHP

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

検証環境

  • AWS EC2 t2.nano (512MB RAM) 2台(Apache検証用 と NGINX検証用)
  • Amazon Linux 2016.09
  • Apache の場合
    • sudo yum install php70PHP 7.0.11 と Apache 2.4.23 をインストール
    • sudo service httpd startApache 起動
  • NGINX の場合
    • sudo yum install php70PHP 7.0.11 と Apache 2.4.23 をインストール
    • sudo yum install php70-fpmPHP-FPM をインストール
    • sudo yum install nginx で NGINX 1.10.1 をインストール
    • sudo service php-fpm startPHP-FPM 起動
    • sudo service nginx start で NGINX 起動

検証結果

再起動方法 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 を流したところバックグラウンドの処理が死んでしまってビビったことがあるのを思い出しました。今だから言える。

追記@2016.11.10

再起動方法 sleep CPU資源を食う処理 バックグラウンド
sudo service php-fpm reload 死ぬ 死ぬ 死なない
sudo service php-fpm restart 死ぬ 死ぬ 死なない

例えば php.ini とかを変更する際は php-fpm を再起動することになるでしょう。その結果はご覧の通りです。やっぱり Apache の方がええんかな…?