シェルスクリプトでのリトライ処理とロック処理
サーバ運用で手動でApache再起動のような対応は辛いので アラートを検知したら自動でApache再起動を実施し、 メールで知らせてくれるスクリプトを書きたいと思い、 リトライ処理やロック処理をシェルスクリプトでどうやるか調べたのでまとめます。
リトライ処理
変数でリトライ回数とリトライ間隔を決めて whileループでカウントを1ずつ増やし、 sleepコマンドの引数にリトライ間隔の変数を与えることで リトライ処理を実装できた。
## リトライ処理 RETRY_COUNT=1 # リトライ回数 RETRY_INTERVAL=1 # リトライ間隔1秒 while [[ $COUNT -ne $RETRY_COUNT ]] do COUNT=`expr $COUNT + 1` sleep $RETRY_INTERVAL done
ロック処理
こちらの記事が参考になりました。https://heartbeats.jp/hbblog/2013/10/atomic03.html#more
シンボリックリンクを作成するときに、作成先にすでにファイルが存在するとエラーとなります。そのため、ロックファイルをシンボリックリンクとして作成を試みれば、ロックファイルが存在すればエラーが発生するため、ロックファイルが存在すると判断し処理を中断できます。ロックファイルが存在しなければ、ロックファイルがシンボリックリンクとして作成されます。「ロックファイルの確認」と「ロックファイルの作成」が同時に行われるため、安全にロックすることができるのです。普通のファイルとしてロックファイルを作成する方法での問題はシンボリックリンクの場合は起きません。
以下のようにシンボリックリンクを作成することでアトミックにロックファイルを作成することができます。
#!/bin/bash LOCK_FILE=$HOME/tmp/file.lock ## ロックファイルの確認と作成 if ! ln -s $$ $LOCK_FILE; then echo "LOCKED" exit 0
このようにロックファイルの確認と作成を別々に行うとアトミックなファイルの扱いにはならないので要注意です。
## ロックファイルの確認 if [ -f $LOCK_FILE ]; then echo "LOCKED" exit 1 fi
それでは実際にリトライ処理とロック処理を使ってシェルスクリプトを書いてみましょう。 Nagios監視でcheck_httpが何度か失敗し、check_loadでも失敗したら Apache再起動を実行し、1分間はApache再起動が実行されないスクリプトを書いてみます。 これをCronなどで3分毎に実行させればWEBサーバで応答に時間がかかっている時の障害対応を自動化できますね。 ロックファイルを設置して排他制御を行うことで、Apache再起動が何度も実行されないように実装ができます。
#!/bin/bash set -uo pipefail HOSTNAME=$(uname -n) MAIL_ADDRESS_TO="メールアドレス" LOCK_FILE="$HOME/restart.lock" RETRY_COUNT=5 # リトライ回数 RETRY_INTERVAL=5 # リトライ間隔5秒 COUNT=0 ## ロックファイルの確認 ## なければロックファイルの作成 if ! ln -s $$ $LOCK_FILE; then echo "LOCKED" exit 0 fi /usr/lib64/nagios/plugins/check_http -w 5 -c 7 -H localhost -u "/" -s "</html>" RETURN_HTTP=$? if [[ ${RETURN_HTTP} -ne 0 ]]; then ## check_httpの応答判断のリトライ処理 while [[ $COUNT -ne $RETRY_COUNT ]] do COUNT=`expr $COUNT + 1` sleep $RETRY_INTERVAL /usr/lib64/nagios/plugins/check_http -w 5 -c 7 -H localhost -u "/" -s "</html>" RETURN_HTTP=$? if [[ ${RETURN_HTTP} -eq 0 ]]; then exit 0 else continue fi done ## リトライ5回繰り返してもcheck_http監視がOKでないなら以下の再起動処理に進む if [[ ${RETURN_HTTP} -ne 0 ]]; then /usr/lib64/nagios/plugins/check_load -w 2,2,2 -c 3,3,3 RETURN_LOAD=$? if [[ ${RETURN_LOAD} -ne 0 ]]; then echo "/etc/init.d/httpd restart" RETURN=$? if [[ ${RETURN} -ne -0 ]]; then RESULT="Failed" else RESULT="Success" fi SUBJECT="${HOSTNAME} httpd restart ${RESULT}" BODY="${HOSTNAME} restart apache ${RESULT}" echo "${BODY}" | mail -s "${SUBJECT}" ${MAIL_ADDRESS_TO} ## 再起動後は1分スリープ後にロックファイルの削除 sleep 60 rm -f $LOCK_FILE fi fi fi
障害対応の自動化で他によいものがあれば教えて下さい。 また、今回のアトミックなファイルの取扱いの考え方は自分ひとりではなかなか気づかなかったです。