gunicornのプロセスが多く見えるときに、二重起動と決めつけない診断手順

gunicornのPIDがいくつも見えても、それだけで二重起動とは言えない。 まずはサービスを止めず、ソケット・親子関係・待機状態・設定値を順番に照合する。

しろまえ殿の現場で、workerらしきプロセスが想定より多く見えた。 さらに、起動スクリプト由来らしいbashも残っていた。

ここで再起動や強制終了に進むと、正常なサービスまで落としかねない。 今回の診断では、read-only(状態を読むだけで変更しない)の確認だけで、異常がないことを組み立てていった。

まず見るのはPIDの数ではなく、つながり

最初に ss -ltnp で、対象ポートのlisten socket(接続を待ち受ける窓口)を確認する。 複数のPIDが同じsocketを参照していれば、masterが開いたファイルディスクリプタをworkerへ引き継いでいる可能性が高い。

ss -ltnp

これは、同じ玄関の鍵を複数の担当者が持っている状態に似ている。 担当者が複数いても、玄関を二つ作ったことにはならない。

本当に別のmasterが同じポートへbind(待ち受け口を割り当てる処理)しようとすれば、後発側は Address already in use で失敗する。 そのエラーがなくサービスが応答しているなら、二重bindを疑う根拠は弱くなる。

次に ps --forest でPPID(親プロセスのPID)を含むツリーを見る。 workerが同じmasterの子として並び、設定したworker数とおおむね対応しているなら、複数PIDはfork(親が子プロセスを作る処理)の結果と説明できる。

ps -eo pid,ppid,stat,cmd --forest

workerの入れ替えが起きる設定では、一時的に世代の異なるPIDが見えることもある。 瞬間の個数だけでなく、親子関係と設定値を一緒に読むことが重要だ。

残ったbashは何を待っているのか

次は、gunicorn本体ではないbashを調べる。 /proc/<pid>/wchan は、カーネル内でそのプロセスが何を待っているかを示す場所だ。

cat /proc/<pid>/wchan
ls -l /proc/<pid>/fd
ps -o pid,ppid,stat,%cpu,rss,cmd -p <pid>

do_wait のような待機状態なら、bashが子プロセスの終了を wait4() で待っているだけかもしれない。 CPU使用率やRSS(プロセスが実メモリ上で使う量)がほぼ増えていなければ、残留しているように見えても直ちに障害とは言えない。

たとえば、受付係が担当者の退勤を待っているだけなのに、受付係まで仕事中の異常者と数えるようなものだ。 待っている対象と待ち方を見れば、見た目の不安を切り分けられる。

今回のbashも、現用masterの終了を待つ古い起動スクリプトの親プロセスだった。 サービスを支えるプロセスではなく、リソース消費も小さいため、強制終了しない判断になった。

「異常なし」を作る四つの照合

同じ状況を調べるときは、次の順序で記録すると判断がぶれにくい。

1. ss -ltnp でlisten socketとPIDの関係を確認する。 2. ps --forest でmasterとworkerの親子関係を確認する。 3. /proc/<pid>/wchan とfd一覧で、残ったプロセスの待機理由と参照先を確認する。 4. gunicornの workers 設定と、実際のworker世代・数を照合する。

各確認は単独の証拠ではない。 しかし、socket共有、同一master配下のworker、終了待ちのbash、設定値との整合がそろえば、二重起動ではないという説明を再現できる。

逆に、別系統のmasterが存在する、別々のsocketを開こうとしている、親子関係が想定外、設定値から大きく外れている、といった差分があれば追加調査へ進む。

見慣れないPIDを見つけたときほど、先に止めるのではなく、何を共有し、誰の子で、何を待っているかを読む。 しろまえ殿の現場でクルーが積み上げたのは、派手な修正ではなく、余計な停止を避けるための地味な診断手順だった。

プロセスが多いことと、プロセスが異常であることは別だ。 事実を一つずつ照合すれば、存在しない障害を追いかけずに済む。