「幽霊ロード」の謎
ある金曜日の午後4時30分、本番環境のデータベースサーバーの1つが極端に低速化しました。モニタリングのアラートは悲鳴を上げており、わずか4コアのCPUを搭載したマシンで、1分間のロードアベレージが15.0まで急上昇していました。私はログインしてtopを実行し、暴走したプロセスがサイクルを食いつぶしているのを予想していましたが、目に入ったのは98%のアイドル時間(idle time)でした。CPUは実質的に休暇中で、システムは単純なlsコマンドの実行にさえ苦労している状態でした。
この状況は、経験豊富なシステム管理者でさえ戸惑わせることがよくあります。私たちは通常、「ロードアベレージ」と「CPU使用率」を同一視しがちですが、これらは別個のメトリクスです。ロードアベレージは、カーネルの実行キューにあるプロセスの数を追跡します。これには、CPUを使用しているタスク、CPUを待っているタスク、そしてI/Oによってブロックされているタスクが含まれます。ロードが高いのにCPUが低い場合、ボトルネックは計算処理ではなく、キューそのものにあります。
キュー vs. ワーカー
これを解決するには、Linuxカーネルがどのようにロードを計算しているかを理解する必要があります。カーネルは主に2つの状態にあるプロセスをカウントします。
- R (Running/Runnable): 現在CPUコアを使用している、または実行の順番を待っているタスク。
- D (Uninterruptible Sleep): ハードウェア(通常はディスクやネットワークI/O)の応答を待っているタスク。
CPU使用率が無視できるほど低い場合、ロードを押し上げているのはD状態です。これらのプロセスは、リソースの応答待ちで立ち往生しています。深いスリープ状態にあるため、カーネルはそれらを中断(interrupt)できません。D状態のプロセスはkill -9でさえ終了させることができず、ハードウェアが最終的にシステムコールに応答したときにのみ消滅します。
I/O待ちのボトルネック
I/O待ち(%iowait)は、最も頻繁に見られる原因です。これは、保留中のすべてのタスクがディスクの読み書きで停滞しているため、CPUがアイドル状態であることを示しています。これは、SATA SSDが500MB/sの限界に達したり、メカニカルドライブが故障し始めたりしたときに発生します。負荷の高いウェブサーバーで、%iowaitが20%まで上昇するのを見たことがありますが、これだけで高性能なマシンが90年代のデスクトップのように感じられるほど重くなります。
ゾンビプロセスの真実
経験の浅い管理者は、ゾンビプロセス(Z状態)がロードを膨らませているのではないかと心配することがよくあります。しかし、そうではありません。ゾンビはすでに死んでいます。プロセステーブルの小さなスロットを占有しますが、CPU、メモリ、I/Oは消費しません。ゾンビの数が多い場合は親アプリケーションにバグがあることを示唆しますが、ロードアベレージが20.0になる原因には決してなりません。
戦術的な診断ワークフロー
CPUがアイドルなのにロードが高い場合、私はパイプの詰まりを見つけるために、以下の特定のコマンドシーケンスを実行します。
1. ディスクの飽和状態を確認する
まずはiostatを使用して、ストレージが圧倒されていないか確認します。コマンドがない場合は、sysstatパッケージをインストールしてください。
iostat -xz 1
%util列に注目してください。CPUが何もしていないのにディスクの使用率が95〜100%に張り付いているなら、それが問題の原因です。最近、バックアップスクリプトがバスを飽和させ、CPUが90%アイドルであるにもかかわらずロードが12.0に達したサーバーを診断したことがあります。
2. 原因となっているプロセスを特定する
I/Oのボトルネックが確認できたら、iotopを使用して原因となっている特定のプロセスを見つけます。これはtopのディスクスループット版のようなツールです。
sudo iotop -o
ここで-oフラグは不可欠です。アイドル状態のプロセスを非表示にし、現在ディスクやクラウドボリュームを激しく叩いているプロセスだけを強調表示します。
3. 応答のないネットワークマウントを探す
もしiotopでローカルディスクのアクティビティが低い場合は、プロセスがNFSマウントなどのリモートリソースを待っている可能性があります。以下のコマンドで、D状態で停止しているプロセスを見つけることができます。
ps aux | awk '$8 == "D" { print $0 }'
ハングアップしたNFSサーバーは、典型的な「ロードキラー」です。そのマウントにアクセスしようとするすべてのプロセスはD状態になり、ネットワークタイムアウト(数分かかることもあります)が発生するまでそのままの状態になります。
解決策の比較
修正方法は、診断結果によって完全に異なります。以下は一般的なシナリオのクイックリファレンスです。
| 原因 | 症状 | 解決策 |
|---|---|---|
| ディスクの飽和 | iostatで高い %util | NVMeへの移行、DBインデックスの最適化、またはバックグラウンドタスク의 制限。 |
| メモリのスワップ | 高い iowait + 高い Swap使用率 | RAMの増設、またはアプリケーションのメモリ制限の引き下げ。 |
| 応答のないNFS | D状態のプロセス + ネットワーク遅延 | 応答のない共有をアンマウントするか、’soft’マウントオプションを使用する。 |
| ハードウェアの故障 | dmesgにI/Oエラー | すぐにSMARTログを確認し、ドライブを交換する。 |
より良い長期的な戦略
目先の遅延を直すのは戦いの半分に過ぎません。再発を防ぐために、2つの具体的なシステム調整をお勧めします。まず、swappinessを調整してください。サーバーが早い段階でディスクへのスワップを開始すると、I/O待ちが急増します。私はほとんどの本番環境Linuxマシンで、RAMを優先するためにこれを10に設定しています。
sudo sysctl vm.swappiness=10
次に、Wait IOに特化したアラートを設定してください。合計ロードだけを監視するのではなく、%iowaitが3分以上にわたって15%を超えた場合にダッシュボードが赤くなるようにします。これにより、システムが反応しなくなる前に、故障しかけているディスクや暴走したデータベースクエリを捉えることができます。CPU使用率を伴わない高いロードは、カーネルが「配管が詰まっている」と伝えているサインです。作業員(ワーカー)を見るのをやめて、パイプを確認し始めましょう。

