深夜2時、Webサーバが沈黙した
状況
あなたは従業員5人の小さな雑貨ECサイトを一人で支えるインフラ担当。サーバはVPS上のweb01が1台きりで、代わりに見てくれる人はいない。深夜2時3分、監視ツールからスマホに「応答時間が30秒を超過」の通知が届いた。眠い目をこすりながらノートPCを開き、web01にSSHでログインする。
第1幕 異変
SSHの接続にすらいつもより時間がかかる。プロンプトが返ってきた頃には胸騒ぎが確信に変わりつつあった。サーバの中で何かがリソースを食い尽くしている。だが憶測で動いてはいけない。まずは数字で全体像をつかむ。それが夜中の障害対応の鉄則だ。
uptimetop -b -n 1 | head -n 12ps aux --sort=-%cpu | head -n 5第2幕 追跡
report.shは毎晩の売上レポートを作る自作スクリプトだ。いつもは1分で終わるはずが、今夜は7分たっても走り続けている。cronの設定では、出力を /var/log/app/report.log に書いているはずだった。プロセスを止める前に、まず何が起きているのかログを見に行く。
ls -lh /var/log/app/tail -n 3 /var/log/app/report.logps -fp 4721ls -l /var/tmp/report.lock第3幕 対処と教訓
原因は見えた。残骸ロックによる無限リトライ。焦らず手順を決めてから動く。(1)暴走中の2プロセスを穏当に止める、(2)残骸ロックを消す、(3)負荷が下がることを数字で確認する。killの前にpsで正体を確認する——さっき済ませたあの一手が、ここで効いてくる。
kill 4721 4988ps -p 4721 4988rm /var/tmp/report.lockuptimecrontab -l振り返り
毎日02:00にcronから起動される売上レポートスクリプトreport.shが、約1か月前の異常終了で残っていたロックファイルを検知し、待ち時間なしの無限リトライに突入していた。本体と子プロセスの2つが2コアをほぼ占有し、同じWARN行を書き続けてreport.logは12GBまで肥大、Webサイトの応答が悪化した。SIGTERMでの停止と残骸ロックの削除で復旧し、ロードアベレージは平常値に戻った。
学び
- 調査はuptime(全体)→top(誰が)→ps(正体)の順で、広い視野から段階的に絞り込む
- killの前に必ずps -fpでPIDの正体を確認する。打ち間違い1つで無関係なサービスを殺しかねない
- killはまずSIGTERM。-9(SIGKILL)は後片付けの機会を奪う最終手段
- 同じログ行が高速に繰り返されるのは、暴走ループの典型的なサイン
再発防止
- リトライ処理には必ずsleepと回数上限を入れる
- ロック管理をflockコマンドに置き換え、プロセス終了時に自動解放されるようにする
- ログサイズとロードアベレージの監視アラートを設定し、暴走を早期検知する