はじめに
killコマンドでJava Virtual Machine(JVM)メモリ情報の出力方法があるの知ってますか?
知識として知らないと、本番のトラブルシュートでプロセスに対してkill -quit 12345なんて打てないです。
たとえば-quitをquitと実行すると大惨事になります。環境はLinuxで動くJVMです。
障害解析のためにスレッドのダンプが必要になりました
ある日、本番環境でアプリケーションが固まりました。
CPUは高くない、メモリも枯れていない。それでもレスポンスが返ってこない。
外から見える情報だけでは、もう何も分からない状態です。
次の一手が「スレッドダンプの取得」です。
ただ、ここで手が止まります。
「本番環境でkillコマンド実施しても大丈夫?」
プロセスを殺すコマンドという認識しかない状態で、本番に対して実行するのは怖い。
一歩間違えれば、その瞬間にサービスが落ちます。そして、大変なことが・・・
だから調べてみた
判明したのは、そもそもの認識が違っていたということでした。
kill はプロセスを殺すコマンドではなく、「シグナルを送るコマンド」でした。
そして、シグナルごとに意味がまったく違いました。
JVMでは、このシグナルを使って内部状態を吐き出させることができようです。
例えばこれです。
kill -3 <PID>
or
kill -quit <PID>
これを実行すると、プロセスは終了しません。
代わりに、スレッドダンプをログに出力します。
つまりこれは「停止命令」ではなく、「中身を見せろ」という合図です。
だからkillじゃなくてsendsignalだったらよかったのに・・・
killコマンドで送れる他のシグナルは?
シグナルは定義されています。
スレッドダンプを取得する
kill -3 <PID>
- JVMがスレッド状態を出力
- デッドロックや待ち状態を確認できる
- 本番でも安全に使える
正常終了させる
kill -15 <PID>
- graceful shutdown
- アプリケーションの終了処理が実行される
- killコマンド のオプション省略した既定値です
強制終了させる
kill -9 <PID>
- 即時終了
- 後処理なし
- 最終手段でよく使うことがある
ユーザ定義シグナル(応用)
kill -USR1 <PID>
kill -USR2 <PID>
これはアプリケーション側がどう実装しているか次第です。
- メモリ情報を出す
- デバッグログを有効化する
- 状態をダンプする
仕込まれていれば強力な観測手段になります。
でもkillを使うのは抵抗がある。
とはいえ、本番で kill を手打ちするのはやはり怖いです。
特に数字1つのミス、ハイフンの付け忘れで結果が変わるので、最初から安全な操作だけをまとめたシェルを用意します。
#!/bin/bash
PID=$1
if [ -z "$PID" ]; then
echo "Usage: $0 <PID>"
exit 1
fi
echo "[INFO] Thread dump start: $PID"
kill -3 "$PID"
sleep 3
kill -3 "$PID"
echo "[INFO] Done. Check stderr or logs."
ls -l /proc/$PID/fd/2
やっていることは単純ですが、危険な操作を排除できる意味は大きいです。
まとめ
最初は「killは危険なコマンド」という認識でした。
しかし実際には、
- シグナルを理解すれば安全に使える
- JVMでは観測手段として非常に有効
- 準備しておけば本番でも落ち着いて使える
という性質のものです。
でも、本番で打つのは怖いので、小さなシェルを準備して安全に行きたいですね。