hhvm プロセスはあるけど http(s) 応答がないときの monit スクリプト
検証環境
- Conoha で配っている kusanagi ディストリビューション(CentOS7)を使用
- hhvm + apache + monit は同一サーバーに配置
-
/var/log/monit.log
など kusanagi ディストリビューションの設定です - もうすでに WordPress などが稼働しているものとします
- kusanagi 自身のインストール方法には触れません
起きている問題と解決する monit 設定ファイル
PHP 実行環境 hhvm で WordPress を 3 つ動かしたあたりからやたら hhvm が落ちだします。そういうのは想定済みたいで、kusanagi 標準添付の monit の hhvm.conf
では hhvm の無応答またはプロセスが落ちたことを検出して再起動をかけくれます。しかし、時々次のような現象が起きます:
- hhvm プロセスは残ったままで
- hhvm のポート(9000/tcp)も開いたまま
- でも apache 経由でアクセスすると一切応答がない
- この状態で
service hhvm stop
するとやたら時間がかる- 一番ひどいときは 180 秒くらい
- hhvm を再起動すると復活するつまり apache の問題ではない
以上、hhvm プロセスが残ったまま http(s) の応答がないケースにも対応させるために以下 hhvm.conf
の置き換えで アプリケーション層 にて再起動を判断し、また、service hhvm stop
にやたら時間がかかる現象にも対応します:
check host heartbeathhvm with address heartbeat.selfnavi.com
start program = "/bin/systemctl start hhvm.service"
stop program = "/bin/systemctl stop hhvm.service" with timeout 360 seconds
depends on httpd
if failed
port 80
protocol http
and request /
with content = "It works!"
with timeout 3 seconds
then restart
if 3 restarts within 3 cycles then unmonitor
group hhvm
heartbeat.selfnavi.com
は生死判定をするサイトで、同一サーバー内に設置してください。各自設置時はこの名前からは変更しなければなりませんが、この記事では heartbeat.selfnavi.com
とします。 wget で It works! が出力されることを確認しときます。
<?php
echo "It works!";
$ wget -qO - http://heartbeat.selfnavi.com
It works
以上でわかればここで終わり。もう少し詳しい説明が必要なら読み進めてください:
- 生死判定をするサイトの設置
- monit の設定
-
/etc/monit.d/hhvm.conf
についての検証
生死判定をするサイトの設置
-
kusanagi コマンドで apache の設定まで終わらせます
- Webサイトで使用するホスト名(FQDN) はなんでも構わないのでご自身のものとしてください
- 上記 FQDN は kusanagi により
/etc/hosts
に追記され、 127.0.0.1 を指すようになります - データベースを作らないと先に進んでくれませんので後でけします
# kusanagi provision --lamp heartbeat ターゲットディレクトリは /home/kusanagi/heartbeat に変更されました。 ↵ Webサイトで使用するホスト名(FQDN)を入力してください。 例) kusanagi.tokyo heartbeat.selfnavi.com Webサイトで使用するホスト名(FQDN)をもう一度入力してください。 heartbeat.selfnavi.com ↵ Let's Encryptを使用される場合、Let's Encrypt の使用規約に同意される必要があります。 使用規約に同意される場合、あなたのメールアドレスを入力してください。同意されない場合、Enterキーを二回押してください。 使用規約は次のURLより確認できます: https://letsencrypt.org/repository/ [Enter] メールアドレスを再入力してください。 [Enter] データベース名を入力してください。 heartbeat データベース名を再度入力してください。 heartbeat heartbeat のユーザー名を入力してください。 heartbeat heartbeat のユーザー名を再度入力してください。 heartbeat データベースユーザ'heartbeat'のパスワードを入力してください。[a-zA-Z0-9.!#%+_-]の文字列が使用できます。最小は8文字以上です。 heartbeat 再度 'heartbeat' のパスワードを入力してください。 heartbeat Job for nginx.service invalid. heartbeat のプロビジョニングは完了しました。heartbeat.selfnavi.com にアクセスし、lampをインストールしてください! 完了しました。
-
kusanagi コマンドで作ってしまったデータベースを消します
-
your_mysql_root_password
は、ご自身の mysql root パスワードに置き換えてください
$ mysql -uroot -pyour_mysql_root_password Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 1847575 Server version: 10.0.29-MariaDB-wsrep MariaDB Server, wsrep_25.16.rc3fc46e ↵ Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others. ↵ Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. ↵ MariaDB [(none)]> drop user 'heatbeat'@'localhost'; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> drop database heatbeat; Query OK, 0 rows affected (0.48 sec) MariaDB [(none)]> exit
-
-
生きていると応答をする php スクリプトの配置
/home/kusanagi/heartbeat/DocumentRoot/index.php<?php echo "It works!";
-
hhvm の設定(
/etc/hhvm/php.ini
にhhvm.server.safe_file_access = true
時のみ)-
/etc/hhvm/php.ini
にhhvm.server.safe_file_access = true
の行が あるときのみ -
hhvm.server.safe_file_access = true
自身を追記する必要はありません/etc/hhvm/php.inihhvm.server.safe_file_access = true hhvm.virtual_host[heartbeat[prefix] = heartbeat.selfnavi.com hhvm.virtual_host[heartbeat][overwrite][server][allowed_directories][] = /home/kusanagi/heartbeat/DocumentRoot
-
もし追記したのであれば
# service hhvm restart
-
-
動作確認
# service httpd reload # exit $ wget -qO - http://heartbeat.selfnavi.com It works
monit の設定
-
要らない設定ファイルを保存する
disable
ディレクトリを作成し、元のhhvm.conf
を退避します。# cd /etc/monit.d # mkdir disable # mv hhvm.conf disable/hhvm.conf.orig
-
/etc/monit.d
には 500 エラーを検出するよう kusanagi が設定ファイルを作成しているはずですが、わたしは jetpack から監視しているのですべてdisable
ディレクトリにいれてます。/etc/monit.d/hhvm.conf
を上記の通り新規で作成し、結局、次のようになりました:# ls -la total 36 drwxr-xr-x 3 root root 96 Jul 11 16:17 . drwxr-xr-x. 100 root root 8192 Jul 11 10:39 .. -rw------- 1 root root 351 Sep 6 2017 alert drwxr-xr-x 2 root root 4096 Jul 12 10:06 disable -rw-r--r-- 1 root root 431 Jul 11 15:02 hhvm.conf -rw------- 1 root root 175 Mar 7 2017 httpd.conf -rw-r--r-- 1 root root 51 Sep 13 2015 logging -rw- ------ 1 root root 175 Mar 7 2017 nginx.conf
-
apache を使っているので nginx を監視しないようにし、新しくいれた
hhvm.conf
を有効にします:# monit start all # monit unmonitor nginx # monit summary The Monit daemon 5.14 uptime: 19h 55m ↵ Program 'nginx' Not monitored Program 'httpd' Status ok Remote Host 'heartbeathhvm' Online with all services System 'kusanagi.cs2cloud.internal' Running
/etc/monit.d/hhvm.conf
についての検証
動作について説明しておきましょう:
check host heartbeathhvm with address heartbeat.selfnavi.com
start program = "/bin/systemctl start hhvm.service"
stop program = "/bin/systemctl stop hhvm.service" with timeout 360 seconds
depends on httpd
if failed
port 80
protocol http
and request /
with content = "It works!"
with timeout 3 seconds
then restart
if 3 restarts within 3 cycles then unmonitor
group hhvm
- monit で指定される間隔(
/etc/monitrc
のdaemon
パラメータ: 30 秒)で http://heartbeat.selfnavi.com/ にアクセスして、 It works! という文字列が 3 秒以内に応答されることを確認する。- もし、3 秒以内に It works! が戻ってこなければ、hhvm の再起動をかける
- 500 エラーでも hhvm の再起動
- hhvm の再起動は stop, start の順で、stop 時は 360 秒まつ。
- 再起動を 3 回繰り返しても条件が満たさなければ、監視を停止する
stop program = "/bin/systemctl stop hhvm.service" with timeout 360
hhvm を停止させる際 /bin/systemctl stop hhvm.service
が完了するまで最大 360 秒待ってくれるという意味です。 hhvm がなかなか止まってくれない状態を再現するために hhvm.service
に
ExecStopPost=/bin/sleep 50
TimeoutStopSec=360
を挟みます。全体は以下のようになります( TimeoutStopSec="infinity"
も あるらしい のですけど、認識してくれませんでした):
[Unit]
Description=HHVM virtual machine, runtime, and JIT for the PHP language
Documentation=http://www.hhvm.com/
After=network.target remote-fs.target nss-lookup.target
[Service]
ExecStart=/usr/bin/hhvm --mode daemon
ExecStopPost=/bin/sleep 50
TimeoutStopSec=360
[Install]
WantedBy=multi-user.target
書き換えたら
# systemctl daemon-reload
index.php
を It works! 以外に 書き換えて再起動条件を作る。 with timeout 360 seconds
のおかげで、再起動条件検出から hhvm の停止まで根気よく待ってくれる。
<?php
echo "It works.";
[JST Jul 11 20:01:29] error : 'heartbeathhvm' failed protocol test [HTTP] at [heartbeat.selfnavi.com]:80/ [TCP/IP] -- HTTP error: Regular expression doesn't match: No match
[JST Jul 11 20:01:29] info : 'heartbeathhvm' trying to restart
[JST Jul 11 20:01:29] info : 'heartbeathhvm' stop: /bin/systemctl
with timeout 360 seconds
がなかったらどうなるか
stop program = "/bin/systemctl stop hhvm.service" with timeout 360 seconds
stop program = "/bin/systemctl stop hhvm.service"
# monit reload
Reinitializing monit daemon
結果だけみると、再起動してくれるのだが:
[JST Jul 11 20:57:14] error : 'heartbeathhvm' failed protocol test [HTTP] at [heartbeat.selfnavi.com]:80/ [TCP/IP] -- HTTP error: Regular expression doesn't match: No match
[JST Jul 11 20:57:14] info : 'heartbeathhvm' trying to restart
[JST Jul 11 20:57:14] info : 'heartbeathhvm' stop: /bin/systemctl
[JST Jul 11 20:57:44] error : 'heartbeathhvm' failed to stop (exit status -1) -- Program /bin/systemctl timed out
[JST Jul 11 20:58:14] error : 'heartbeathhvm' failed protocol test [HTTP] at [heartbeat.selfnavi.com]:80/ [TCP/IP] -- HTTP error: Server returned status 503
[JST Jul 11 20:58:14] info : 'heartbeathhvm' trying to restart
[JST Jul 11 20:58:14] info : 'heartbeathhvm' stop: /bin/systemctl
[JST Jul 11 20:58:15] info : 'heartbeathhvm' stopped
[JST Jul 11 20:58:15] info : 'heartbeathhvm' start: /bin/systemctl
stop 時にデフォルトの待ち時間 30 秒を経過したところでタイムアウトが記録されている(動作解説 CONFIGURATION EXAMPLES のあたり)ここで monit は動作を打ち切り start はしない:
failed to stop (exit status -1) -- Program /bin/systemctl timed out
タイムアウト後再び monit から監視がはいるが hhvm は stop のまま、httpd は生きていているので 500 が戻ってくる
failed protocol test [HTTP] at [heartbeat.selfnavi.com]:80/ [TCP/IP] -- HTTP error: Server returned status 503
500 の応答を受けもう一度再起動がかかるが、hhvm は stop のままなのでタイムアウトにはならず、再起動に成功する。
with timeout 3 seconds
if failed
port 80
protocol http
and request /
with content = "It works!"
with timeout 3 seconds
生死判定をするサイトに応答に 5 秒かけるよう細工を施す:
<?php
sleep(5);
echo "It works!";
Resource temporarily unavailable として処理されるようです:
[JST Jul 11 16:18:24] error : 'heartbeathhvm' failed protocol test [HTTP] at [heartbeat.selfnavi.com]:80/ [TCP/IP] -- HTTP: Error receiving data -- Resource temporarily unavailable
[JST Jul 11 16:18:24] info : 'heartbeathhvm' trying to restart
[JST Jul 11 16:18:24] info : 'heartbeathhvm' stop: /bin/systemctl
[JST Jul 11 16:19:16] info : 'heartbeathhvm' start: /bin/systemctl
if 3 restarts within 3 cycles then unmonitor
3 回再起動(within 3 cycles)で 3 回リスタート条件を満たす(3 restarts)ときは監視からはずされる(unmonitor)。
index.php
を It works! 以外 に書き換えて再起動条件を作る。
<?php
echo "It works.";
[JST Jul 11 21:51:33] error : 'heartbeathhvm' failed protocol test [HTTP] at [heartbeat.selfnavi.com]:80/ [TCP/IP] -- HTTP error: Regular expression doesn't match: No match
[JST Jul 11 21:51:33] info : 'heartbeathhvm' trying to restart
[JST Jul 11 21:51:33] info : 'heartbeathhvm' stop: /bin/systemctl
[JST Jul 11 21:51:33] info : 'heartbeathhvm' start: /bin/systemctl
[JST Jul 11 21:52:08] error : 'heartbeathhvm' failed protocol test [HTTP] at [heartbeat.selfnavi.com]:80/ [TCP/IP] -- HTTP error: Regular expression doesn't match: No match
[JST Jul 11 21:52:08] info : 'heartbeathhvm' trying to restart
[JST Jul 11 21:52:08] info : 'heartbeathhvm' stop: /bin/systemctl
[JST Jul 11 21:52:08] info : 'heartbeathhvm' start: /bin/systemctl
[JST Jul 11 21:52:43] error : 'heartbeathhvm' failed protocol test [HTTP] at [heartbeat.selfnavi.com]:80/ [TCP/IP] -- HTTP error: Regular expression doesn't match: No match
[JST Jul 11 21:52:43] info : 'heartbeathhvm' trying to restart
[JST Jul 11 21:52:43] info : 'heartbeathhvm' stop: /bin/systemctl
[JST Jul 11 21:52:43] info : 'heartbeathhvm' start: /bin/systemctl
[JST Jul 11 21:53:14] error : 'heartbeathhvm' service restarted 3 times within 3 cycles(s) - unmonitor