ヘルスチェックにより、正常稼働中のモデルサーバーが1日に8回再起動されました

オペレーション

7月22日、ウォッチドッグによりローカルモデルサーバーが8回再起動されました。そのうちクラッシュを伴うものは1つもありませんでした。モデルを稼働させ続けるはずのチェックが、逆に停止させていたのです。

何が起きたか

モデルサーバーはNVIDIA GB10マシン1台でvLLMを実行し、単一リクエストに対して毎秒約8トークンを生成していました。ウォッチドッグは5分ごとに実際のチャットリクエストを送信し、応答を最大45秒間待ち受けます。連続して5回のチェックに失敗するとサーバーがハングしたと判断され、ウォッチドッグが再起動を実行します。再起動には数分かかり、その間約19 GBの重みデータが再読み込みされます。

その日、バッチジョブがサーバー上で2〜4件のリクエストを数分間占有していました。ウォッチドッグのリクエストはそれらの後ろでキューに入り、タイムアウトして失敗とカウントされました。こうしたチェックが5回続いた後、正常なサーバーが再起動されました。ウォッチドッグが尊重する「ビジー」フラグファイルは存在しましたが、バッチジョブはそれを設定していませんでした。

1回の誤った再起動が次の誤った再起動を招いた経緯

再起動のたびに、進行中のリクエストは500エラー(「cannot schedule new futures after shutdown」)で失敗しました。別のウォッチドッグは500エラーをカウントし、数が多すぎるとサーバーを再起動します。エラーが増えるほど、その動作は早くなります。つまり、誤った再起動が1回発生するたびに、次の再起動がより早く実行されるようになりました。合計4つの独立したウォッチドッグが、5分、10分、15分、30分のタイマーでそのサーバーを再起動できました。

そこから得たルール

ヘルスチェックは、監視対象のリソースを使ってはいけません。モデルサーバーの希少なリソースは、進行中のリクエスト用のスロットです。そのスロットを占有する、またはスロットを待つチェックは、判定すべき負荷の一部になってしまいます。低コストでチェックを行い、サーバーがスタックしていることを確認できた場合のみ再起動してください。

置き換えたチェックの内容

vLLMは独自のカウンタを /metrics で公開しています。新しいチェックはまずそれらを読み取ります。

最初のバージョンでは、生成されたトークン数を進行状況としてカウントしていました。8回のテストに合格しましたが、初回のライブ実行では、サーバーがビジーかつ正常であることが判明しました。実行中のリクエストは2件、2回の読み取りの間で107個の新しいトークンが生成されました。

それ以降の変更点

その違いは明白です。このメモを書いている時点で、両方のモデルサーバーは上限である 12 件のリクエストをそれぞれ処理していました。テストリクエストはキューで待機することになります。新しいチェックは、リクエストを送信せずに、両サーバーをビジーかつ正常(それぞれ毎秒 126 トークンと 101 トークン)と報告しました。

Factory Floor 1.0.2 では、このチェックを models/llm-health.py として提供しています。アイドル、ビジー、スタック、再起動したサーバー、メトリクスを持たないサーバー、プロキシ、および停止したバックエンドに対するテストも含まれています。

更新済み: