VRAMゴーストバスター:どのclose()を呼ぶべきか?
H社のGPUクラスタで、ジョブクラッシュ後にVRAMがゴーストプロセスに占有される問題が発生。調査の結果、S3ストレージ用のFUSEマウントが原因であることが判明しました。ユーザースペースデーモン(rclone mount)がOOMで強制終了された後、カーネルがFUSE接続を正しく中断できなかったため、訓練スレッドがD状態でCUDAコンテキストを保持し続けました。一時的な対策としてFUSE接続を強制中断しましたが、根本原因はファイルディスクリプタリークです。
H社では、訓練ワークロード(特にオンライン強化学習や大規模教師ありファインチューニング)がSkyPilotで管理されるGPUクラスタ上で実行されており、バックエンドにはKubernetesとSlurmが使用されています。典型的なジョブは8×H100ノードを使用したマルチノード分散訓練で、チェックポイントとデータセットシャードはS3に保存され、高スループットでストリーミングする必要があります。
SkyPilotのMOUNT_CACHEDはこのプロセスを簡素化します。S3バケットをPod内のローカルディレクトリとしてマウントし、ローカルディスクへのライトバックキャッシュとrclone mountを使用してS3と非同期同期を行います。訓練コードは通常のファイルシステムとして認識しますが、実際にはFUSEマウントであり、カーネルはすべてのファイルシステムシステムコールをユーザースペースデーモンに中継します。
問題はKubernetesバックエンドで最初に表面化しました。研究者が新たに予約した8×H100ノードでモデルウェイトのロード中にOOMが発生しました。nvidia-smiで確認すると、GPU 0が80 GiBを占有し、他のGPUも数百MiBから1 GiB程度を占有していましたが、関連するPIDはありませんでした。これらのVRAMはゴーストプロセスによって使用されているように見えました。
調査では、containerd CLIを使用して、Podが削除された後も実行中のコンテナをリストアップしました。複数のコンテナが依然としてRUNNING状態でした。さらに、これらのコンテナ内のスレッドがD状態(割り込み不可スリープ)であり、その待機チャネルはrequest_wait_answerであることがわかりました。これはFUSEデバイスドライバで、ユーザースペースデーモンの応答を待つ関数です。訓練プロセスがFUSEマウント上のread()でブロックされ、応答が決して返ってこないことを意味します。
/sys/fs/fuse/connections/ディレクトリを確認すると、複数のFUSE接続に待機者がいる一方で、対応するユーザースペースデーモンが存在しないことがわかりました。通常、デーモンが死亡するとカーネルはfuse_abort_connを呼び出してブロックされた読み取りを-ECONNABORTEDで起動するはずですが、それが発生していませんでした。
強制的に接続を中断(/sys/fs/fuse/connections/*/abortに1を書き込み)すると、ブロックされていたスレッドは即座に終了し、VRAMが解放されました。これによりメカニズムが確認できました。つまり、スタックしたFUSE接続が訓練プロセスを停止させ、CUDAコンテキストを保持させ、VRAMを解放できなくしていました。
さらに分析を進めると、ユーザースペースデーモン(rclone mount)がOOMで強制終了されたものの、カーネルが接続を中断しなかった理由は、fusermount-server(SkyPilotで非特権PodのFUSEマウントを仲介するプロセス)がまだ/dev/fuseのファイルディスクリプタを保持していたためでした。これにより、カーネルはデーモンが死んだことを検出できませんでした。また、fusermount-serverに多数の/dev/fuseファイルディスクリプタが蓄積されていることも確認され、ファイルディスクリプタリークが存在することが示唆されました。
一時的な対策として、アイドルGPUノードのVRAM占有を検出し、AWS SSM経由でfusermount -u --abortを実行してゾンビFUSE接続を強制中断するスクリプトを作成しました。ほとんどのノードは即座に回復しましたが、一部のノードは再起動が必要でした。
このバグはKubernetesバックエンドでのみ発生しました。これはSkyPilotが非特権ユーザーPodのFUSEマウントを仲介するために追加の特権ヘルパーを使用しているためです。ただし、同様のパターンはファイルディスクリプタを仲介する任意の環境で発生する可能性があります。記事では、VRAM占有、スタックしたコンテナ、D状態スレッド、FUSE接続待機者のチェックリストを提供しています。
この事例は、分散訓練インフラストラクチャにおいて、特にデーモンがメモリプレッシャーで強制終了される可能性がある場合、FUSEファイルシステムパスの安定性が重要であることを強調しています。今後の対応として、MOUNT_CACHEDのOOM処理改善とfusermount-serverのファイルディスクリプタリーク修正が予定されています。