代表的な面接トピック

Linux面接:CPU使用率が低いのにロードアベレージが高い理由とその診断方法は?

一般難しい
Offer.cc 編集チーム公開日 更新日

質問

16個の論理CPUを搭載したLinuxサーバーで、ロードアベレージが48、36、18を示している一方、全体(集計)のCPUアイドル率は72%のままです。これはCPUの過負荷を証明していますか?ロードアベレージの仕組みを説明し、CPUキューイング、I/Oまたはカーネル待ち、メモリ圧迫、および可観測性のスコープの不一致をどのように見分けるかを示してください。

プロンプトと対象となる職種

16個の論理CPUを搭載したLinuxサーバーの動作が遅くなりました。uptime48 / 36 / 18というロードアベレージを報告していますが、mpstatは全体(集計)のCPUアイドル率が72%であると報告しています。これがCPUの過負荷を証明しているかを判断し、タスクが実際に待機しているリソースを特定する方法を説明してください。

回答では、Linuxの負荷計算における実行可能タスクと割り込み不能タスクを説明し、1分、5分、15分の値を正しく解釈した上で、タスクの状態、Pressure Stall Information(PSI)、サブシステムメトリクスを使用して以下のケースを区別する必要があります:

  • CPU実行キュー(run queue)が真に混雑している;
  • ローカルストレージ、ネットワークファイルシステム、ドライバ、またはその他のカーネル待機によってタスクがD状態にとどまっている;
  • メモリの回収(reclaim)やスワップ処理によって間接的な待機が発生している;
  • ホストレベルのメトリクスとコンテナまたはサービスレベルのメトリクスが異なるスコープを対象としている。

この質問は、SRE、DevOps、インフラ、システム、およびバックエンドの面接に適しています。16、48、36、18、および72%という数値は演習用の架空の入力値であり、普遍的なアラート閾値ではありません。このシナリオは、メトリクスが同じホストおよび同じ時間枠から取得されたものであることを前提としています。異なるコレクターやcgroupから生成された場合は、解釈する前にスコープを揃えてください。

面接官がテストしていること

第一に、候補者はロードアベレージがCPU使用率(utilization)ではないことを知っている必要があります。Linuxのグローバル負荷は、実行可能タスクと割り込み不能スリープ(uninterruptible sleep)状態のタスクの指数関数的減衰平均です。前者のグループのみが直接CPU需要を表し、後者はCPUがアイドル状態のままでも負荷を上昇させる可能性があります。

第二に、3つの数値には正確な解釈が必要です。これらは過去1分、5分、15分のサンプルの単純な算術平均ではありません。これらの時定数を持つ指数関数的減衰値です。48 > 36 > 18は、最近負荷が上昇したという方向性のある結論を裏付けますが、過去の特定の分における正確なキューの長さを再構築したり、根本原因を証明したりすることはできません。

第三に、優れた診断は合計値からその構成要素や待機場所へと移行します。vmstatのフィールドであるrbを比較し、RおよびD状態のスレッド数をカウントし、wchan、カーネルスタック、PSI、ストレージまたはネットワークファイルシステムのメトリクスを使用してリソースを特定します。単にtopiostatを列挙するだけでは、証拠がどのように結論を変えるかを説明できません。

第四に、候補者は反例を扱える必要があります。ツールはD状態をdisk sleepと表記することが多いですが、割り込み不能な待機はローカルディスクに限定されません。NFS、ファイルシステム、デバイスドライバ、および一部のカーネルリソース待機も現れる可能性があります。%iowaitはCPU時間の計上であるため、低いiowaitはブロックされたタスクの存在を否定しません。

最後に、回答には安全な緩和策と検証ループが必要です。CPUの追加、再起動、プロセスの強制終了、ストレージのアップグレードは、特定の証拠に対してのみ適切です。修正後は、R/Dタスク数、PSI、サブシステムのレイテンシ、ビジネスのテールレイテンシ(tail latency)が一緒に回復するはずです。ロードアベレージが減衰するのを待つだけでは不十分です。

回答前に確認すべき質問

  • メトリクスは同じスコープをカバーしていますか? ロードアベレージは一般にホスト全体を対象としますが、アプリケーションのCPUは単一のコンテナまたはプロセスのみを表している場合があります。まずホスト、cgroup、サービスのメトリクスを比較してください。そうしないと、「高負荷・低CPU」は単なるスコープの不一致である可能性があります。
  • CPUアイドル率は全体(集計)ですか、それともCPUごとの値ですか? 他のCPUがアイドル状態である一方で、1つのCPU、NUMAノード、またはアフィニティによって制限されたワークロードがキューイングされている可能性があります。mpstat -P ALL、アフィニティ、およびcgroupのCPUクォータを調査してください。
  • どのリクエストが、いつ遅延しましたか? ホストのシグナルをユーザーへの影響と結び付けるために、症状をデプロイ、トラフィック、バックアップ、ストレージレイテンシ、マウントの変更、メモリ回収のタイミングと照らし合わせます。
  • RタスクとDタスクのどちらが優勢ですか? CPUがビジーな状態でRタスクが多い場合は、CPU競合を裏付けます。CPUがアイドルな状態でDタスクが多い場合は、割り込み不能な待機を裏付けます。両方が共存することもあるため、スレッドおよびワークロードごとにグループ化します。
  • どのストレージパスが関係していますか? ローカルNVMe、クラウドブロックスレージ、FUSE、NFS、リモートデータベースでは、それぞれ異なる証拠が必要です。iostatは通常のネットワークRPCを確認できず、NFSにはマウントおよびネットワークファイルシステムのメトリクスが必要です。
  • メモリまたは仮想化の圧迫はありますか? スワップイン/スワップアウト、直接回収(direct reclaim)、メジャーフォールト(major fault)、ハイパーバイザのsteal time、cgroupの制限によって、調査の順序が変わります。
  • タスクスタックは安全に読み取れますか? /proc/12345/stack、一部のwchan値、およびプロセスのI/Oデータには追加の権限が必要な場合があります。オーバーヘッドの低いサンプリングから開始し、本番環境で必要な最小限の権限のみを使用してください。

30秒の回答フレームワーク

「ロードアベレージはCPU使用率のパーセンテージではありません。Linuxは実行可能タスクと割り込み不能スリープ状態のタスクをカウントし、1分、5分、15分の時定数で指数関数的減衰平均を計算します。16個の論理CPUで負荷が48であることは、多くのタスクがアクティブであるか、割り込み不能で待機していることを示しています。CPUアイドル率が72%であることから、CPUが飽和していると結論付けることはできません。

私ならまずメトリクスのスコープを揃え、CPUごとの使用率を確認します。次にvmstatを使用して、rの実行可能タスクとbのブロックされたタスクを比較し、RおよびD状態のスレッド数をカウントします。Rタスクが多く、CPU PSIが高く、CPUがビジーであれば、CPUキューイングを示します。Dタスクが多くI/O PSIが高い場合は、wchan、タスクスタック、pidstatiostat、NFSメトリクス、およびカーネルログを調べます。メモリPSI、スワッピング、メジャーフォールトが同時に増加している場合は、メモリ圧迫を調査します。修正後は、負荷の数値が下がるのをただ待つのではなく、ビジネスのp99、R/D数、PSI、サブシステムのレイテンシを検証します。」

ステップバイステップの詳細解説

ステップ1:ロードアベレージを2つのソースに分解する

Linuxのグローバル負荷計算のコア入力は次のように要約できます:

nr_running + nr_uninterruptible

nr_runningには、CPU上で現在実行中のタスクと、実行可能だがスケジューリングを待っているタスクが含まれます。nr_uninterruptibleは、割り込み不能スリープ状態のタスクを表します。/proc/loadavgの最初の3つのフィールドは、このアクティブタスク集団に対する1分、5分、15分の負荷値です。4番目のフィールドは7/1280のようになっており、最初の数値は現在実行可能なスケジューリングエンティティ数、2番目は現在存在するすべてのスケジューリングエンティティ数です。5番目のフィールドは直近に作成されたPIDです。

したがって、「負荷48」は「CPU使用率300%」を意味するわけではなく、現時点で正確に48個のプロセスがキューイングされていることを意味するわけでもありません。これは平滑化されたタスク数のシグナルです。負荷を論理CPU数で割ることは、CPUバウンドなワークロードに対するおおよその飽和の目安にすぎません。D状態のタスクが大きく寄与している場合、その比率はもはやCPUキューを表していません。

カーネルは一定の間隔で指数関数的減衰平均を更新します。新しいサンプルほど重みが大きく、古いサンプルは減衰します。したがって、48 / 36 / 18は以前よりも最近のアクティブタスクが増加したことを示します。原因が解消された後も15分の値は高いまま残ることがあるため、復旧の判断では現在のタスク状態、PSI、およびユーザー向けメトリクスを優先する必要があります。

ステップ2:スコープ、CPUごとの使用率、および現在のキューを揃える

まずは低オーバーヘッドでタイムスタンプ付きの観測から始めます:

bash
nproc
uptime
cat /proc/loadavg
vmstat 1 10
mpstat -P ALL 1 10

vmstatの最初のレポートは通常、起動時からの平均であるため、インシデント発生時の分析にはそれ以降のサンプルを使用します。重要なフィールドは以下の通りです:

  • r:実行可能タスク。CPUがビジーな状態で利用可能なCPUを大幅に上回る値が続く場合、CPUキューイングを裏付けます;
  • b:割り込み不能スリープ状態のタスク。継続的な増加は、調査対象を待機中のリソースへと向けさせます;
  • ussyidwast:ユーザー、システム、アイドル、I/O待機、およびハイパーバイザのsteal time;
  • siおよびso:スワップインおよびスワップアウトのアクティビティ。メモリPSIやフォールトと組み合わせて解釈します。

72%の全体アイドル率であっても、特定の過熱したCPUが隠れている可能性があります。CPU 3に固定された単一スレッドがそのCPUを飽和させている一方で、他の15個のCPUがほぼアイドルのままになっていることがあります。CPUごとの使用率、タスクアフィニティ、コンテナのCPUクォータ、およびスロットリング(throttling)を確認することで、ホスト全体でCPUを追加する必要があるのか、特定CPUの偏りなのかを区別できます。

ステップ3:スレッドごとにRとDをカウントし、待機場所を特定する

1つのプロセス内の複数のスレッドが負荷に寄与するため、スレッドレベルのビューを使用します:

bash
ps -eLo state,pid,tid,ppid,wchan:32,comm --sort=state
ps -eLo state= | sort | uniq -c

Rは実行中または実行可能(running / runnable)を意味します。Dは割り込み不能スリープ(uninterruptible sleep)を意味します。通常、シグナルはタスクがその待機状態を抜けるまで効果を発揮しないため、kill -9を繰り返し発行しても、カーネルリソースが即座に解放されることはなく、有用な証拠も保持されません。

D状態スレッドの集団については、コマンド、親プロセス、cgroup、およびwchanでグループ化します。wchanはスレッドがカーネル内のどこでスリープしているかを示し、ブロックI/O、NFS、ファイルシステム、またはドライバパスへの調査範囲の絞り込みに役立ちます。権限が許可されている場合は、代表的なタスクのカーネルスタックを検査します:

bash
cat /proc/12345/stack
cat /proc/12345/wchan

単一の関数名は根本原因ではありません。同じ待機場所に多数のタスクが集中し、サブシステムのレイテンシやユーザーへの影響と時間的に一致していることが、より強力な証拠となります。また、D状態はアプリケーションが意図的に過剰なI/Oを生成したことを証明するものでもありません。デバイスの障害、到達不能なリモートマウント、または停止したカーネルパスにより、わずかなリクエストレートからでも待機スレッドが多数蓄積することがあります。

ステップ4:PSIを使用して進行を妨げているリソースを特定する

PSIは、CPU、メモリ、またはI/Oの競合によって失われた時間を定量化します:

bash
for resource in cpu io memory; do
  echo "[$resource]"
  cat /proc/pressure/"$resource"
done

someは、少なくとも一部のタスクがリソース上でストールしている時間の割合です。fullは、アイドル状態でないすべてのタスクが同時にストールしている時間の割合です。システムレベルのCPU fullは0として維持され、CPU飽和を推論するために使用すべきではありません。avg10avg60avg300は直近10秒、60秒、300秒の傾向を示し、totalはマイクロ秒単位の累積ストール時間です。

PSIとロードアベレージは異なる疑問に答えます。ロードアベレージは、アクティブまたは割り込み不能で待機しているタスクの数を表します。PSIは、ワークロードが進行できない時間の長さを表します。これらを組み合わせることで、「負荷が高いからCPUを追加する」という短絡的な反応を防ぐことができます。cgroup v2では、対象cgroup内のcpu.pressureio.pressurememory.pressureも確認し、サービスの圧迫をホストのノイズから切り離してください。

証拠を整理するために次のマトリクスを使用します:

観測された組み合わせ最初の仮説次に確認すべき証拠
高CPUビジー、高r、高CPU PSICPU実行キューの競合CPUごとのホットスポット、CPUプロファイル、アフィニティ、クォータ
高CPUアイドル、多数のb/Dタスク、高I/O PSII/Oまたはその他の割り込み不能カーネル待機wchan/スタック、デバイスまたはNFSのレイテンシ、カーネルログ
高メモリPSI、si/soの上昇またはメジャーフォールトメモリ回収またはスワップの圧迫cgroupメモリ、ワーキングセット、回収処理、ストレージ読み取り
高ホスト負荷、対象cgroupの低PSIスコープの不一致または他のテナントの影響cgroup/プロセスごとにタスクとリソースを特定

このマトリクスは出発点であり、自動的な根本原因検出器ではありません。CPU、メモリ、I/Oの圧迫はフィードバックループを形成することがあります。たとえば、メモリ回収によってファイル読み取りがトリガーされ、それがスレッドをD状態に追い込むことがあります。

ステップ5:すべての待機を「ディスクが遅い」で片付けず、関連するサブシステムを調査する

証拠がブロックデバイスを指している場合は、スループット、レイテンシ、キューイング、エラーを調べます:

bash
pidstat -d -p ALL 1 10
iostat -xz 1 10
dmesg -T | tail -200

pidstatはI/Oを発行しているプロセスを特定するのに役立ち、iostatはデバイスおよびパーティションのアクティビティを報告します。すべてのフィールドをデバイスタイプとそのベースラインに照らして解釈してください。たとえば、%utilの値には、あらゆるストレージアーキテクチャに共通する単一の飽和閾値は存在しません。カーネルログ内のタイムアウト、リセット、ファイルシステムエラー、または切断されたデバイスは、キューの深さ単体よりも障害原因に直接結びついています。

wchanまたはマウントポイントがNFS、FUSE、またはネットワークストレージを示している場合は、マウント状態、nfsiostat、クライアントの再送、ネットワークレイテンシ、およびサーバーの健全性を調査します。通常のHTTPやデータベースのRPC待機は通常割り込み可能であり、Linuxのロードアベレージには含まれない可能性があるため、アプリケーションのトレース、コネクションプール、依存関係のレイテンシも同じタイムライン上で追跡する必要があります。

メモリPSI、スワッピング、またはメジャーフォールトが増加した場合は、cgroupのメモリエベント、匿名ページおよびファイルページのワーキングセット、直接回収、スワップデバイスを調査します。より高速なストレージを使用すればスワッピングのコストは削減できるかもしれませんが、メモリ予算を超過したワーキングセットそのものは修正されません。

ステップ6:証拠に基づいて緩和策を講じ、因果関係を検証する

緩和策は、確認された待機リソースに一致させる必要があります:

  • CPUキューの競合:アドミッションの遮断(shed admission)、並行数やバッチ優先度の引き下げ、不適切なアフィニティの解除を行い、測定されたキャパシティモデルに基づいてのみCPUを追加する;
  • ストレージまたはNFSの障害:I/Oの増幅を止め、健全なレプリカまたはマウントパスに切り替え、デバイス、ネットワーク、またはサーバーを修復する;
  • メモリ圧迫:ワーキングセットと並行数を制限し、スラッシング(thrashing)しているワークロードを停止し、互換性のあるキャパシティ境界内でメモリを追加する;
  • スコープの不一致:対象サービスをスケールさせる必要があるかを判断する前に、ノイズの原因となっているワークロードを隔離するか、cgroupクォータを修正する。

再起動によって蓄積されたタスクがクリアされる場合がありますが、有用なスタックやログも消去される可能性があります。根本的なリソースが利用不可能なままであれば、新しいプロセスが再びブロックされます。対応を行う前に、代表的なPID、タスク状態、wchan、PSI、サブシステムのスナップショットを保存し、期待されるメトリクスの変化を明確に定義してください。

完了基準(Acceptance)には、ビジネスのp95/p99およびエラー率の回復、ベースラインに戻ったR/D数、該当するPSIリソースにおける圧力の低下、デバイス/NFS/メモリ/CPUメトリクスの回復、およびバックログの安全な処理完了を含める必要があります。ロードアベレージは徐々に減衰するため、インシデント完了判断の唯一のゲートではなく、回復シグナルの1つとして扱います。

高品質な回答例

「16個のCPUで負荷が48であるという理由だけで、これをCPUの過負荷と呼ぶことはしません。Linuxのロードアベレージは、CPUを実行中または待機中のタスク数に、割り込み不能スリープ中のタスク数を加えたものを平滑化した値です。CPUアイドル率が72%である場合、負荷には多くのD状態の待機が含まれている可能性があり、あるいは集計値によってCPU単位、クォータ、またはメトリクススコープの問題が隠蔽されている可能性があります。

48 / 36 / 18は指数関数的減衰平均です。方向性として、これらは最近アクティブなタスクが増加したことを示しています。これらは3つの独立した時間枠の単純な算術平均ではなく、原因を特定するものでもありません。私ならまず、負荷、CPU、ビジネスレイテンシが同じホストおよび時間枠からのものであることを確認し、mpstat -P ALLを調べて過熱したCPUやsteal timeがないかを確認します。

次に、rおよびbvmstat 1と比較します。rが高く維持され、CPUがビジーで、CPU PSIが高い場合は、CPUプロファイル、アフィニティ、およびcgroupのスロットリングを調査します。CPUがアイドルのままでbが高く、多数のD状態スレッドが存在する場合は、スレッドをコマンドとwchanでグループ化し、代表的なタスクの/proc/12345/stackを検査し、その結果をI/O PSIと照らし合わせます。

仮に多数のスレッドがNFS関連のパスで待機しており、I/O PSIが上昇し、ローカルブロックデバイスのiostatが正常なままであるとします。その場合、ローカルのクラウドディスクをアップグレードするのではなく、マウント、クライアントの再送、ネットワークレイテンシ、およびNFSサーバーを調査します。緩和策としては、関連するバッチジョブの停止、正常なレプリカへの読み取りの切り替え、影響を受けるノードの切り離しなどが考えられます。D状態のプロセスを繰り返し強制終了しても、通常は即座に効果がありません。

修復後は、ビジネスのテールレイテンシとエラー率、R/Dスレッド数、ホストおよびcgroupのPSI、NFSレイテンシ、バックログを確認します。1分、5分、15分の負荷値は時間とともに減衰するため、現在の待機とユーザーへの影響がすでに安定しているなら、15分の値がまだ高いからといって、リスクを伴う変更をさらに行うべきではありません。」

よくある間違い

  • ロードアベレージをCPU使用率として扱う → タスクをカウントしており、割り込み不能スリープを含んでいる → CPU競合を診断する前に、rb、およびRとDを分離する。
  • 負荷がCPU数を超えたら常に過負荷と宣言する → そのルールはCPUバウンドな需要に対する大まかな目安にすぎない → CPUビジー率、CPU PSI、および実行可能キューを組み合わせる。
  • 1、5、15を単純なウィンドウ平均として扱う → Linuxは指数関数的減衰を使用し、古いサンプルを保持する → 3つの値を方向性の把握に使用し、現状は最新のメトリクスで確認する。
  • すべてのDタスクをローカルディスクに帰属させる → NFS、ファイルシステム、ドライバ、その他のカーネル待機も割り込み不能になり得る → wchan、スタック、および対応するサブシステムをトレースする。
  • iowaitが低いためI/Oを除外する → iowaitはCPU時間の計上であり、ブロックされたタスク数ではない → Dタスク、I/O PSI、デバイス、およびリモートストレージのレイテンシを調査する。
  • ホスト平均のCPUのみを見る → 過熱したCPU、アフィニティ、クォータ、または別のcgroupが平均によって隠される可能性がある → CPUごと、ホスト、および対象cgroupのメトリクスを比較する。
  • スタックしたタスクに対してkill -9を繰り返し発行する → シグナルは割り込み不能な操作が復帰するのを待つため、証拠が失われる可能性がある → 証拠を保全し、待機対象となっているリソースを修復する。
  • 単一のwchan値を根本原因と呼ぶ → カーネルスリープの現在の場所を特定するだけである → クラスタリング、時間的相関、およびサブシステムの証拠を必須とする。
  • 回復を宣言する前にロードアベレージが0になるのを待つ → 減衰にはタイムラグがあり、健全なシステムでも負荷0は必須ではない → ユーザーへの影響、現在のタスク、PSI、およびリソースメトリクスから回復を判断する。

フォローアップの質問と回答

フォローアップ 1: CPUアイドル率が高いときに%iowaitも低くなることがあるのはなぜですか?

%iowaitは、システムが未処理のI/Oを計上している間にアイドル状態になっているCPU時間の割合です。これはCPU時間の計上です。CPUが他の作業を実行しているか、通常のアイドル状態にある間に、タスクがNFS、ドライバ、またはその他の割り込み不能なカーネル待機でブロックされることがあります。また、多数のCPU全体で集計されることで、局所的な症状が薄まることもあります。D状態のカウント、I/O PSI、wchan、およびサブシステムのレイテンシを使用してください。低いiowait単体では、I/Oやカーネル待機の存在を除外できません。

フォローアップ 2: コンテナ内部で観測されたロードアベレージは、そのコンテナを表していますか?

表していると思い込まないでください。可視化される負荷および/procのスコープは、ホスト、PIDネームスペース、ランタイム、および監視の実装に依存しますが、アプリケーションのCPUはcgroupスコープである場合があります。ホストおよび対象cgroupのCPU、I/O、メモリPSIに加えてクォータイベントを読み取り、スレッドを各cgroupに帰属させてください。ホストの負荷が高くても対象cgroupに圧迫がない場合、そのサービスをスケールさせても効果がない可能性があります。

フォローアップ 3: 負荷が48でCPUアイドル率が72%の場合、必ず多数のD状態タスクが存在しますか?

いいえ。メトリクスが非同期である可能性、全体のアイドル率が特定の過熱したCPUを隠している可能性、タスクがアフィニティやcgroupクォータによって制限されている可能性、あるいは負荷が下がった直後で指数平均にピークが残っているだけの可能性があります。内訳を判断するには、/proc/loadavg内の現在の実行可能カウント、vmstat r/b、CPUごとの使用率、R/Dスレッド数、および収集タイムスタンプを確認してください。

フォローアップ 4: D状態のプロセスがkill -9でも終了しないことがあるのはなぜですか?

割り込み不能スリープにより、一部のカーネル操作は通常のシグナルによる中断なしにクリティカルフェーズを通過できます。SIGKILLは保留状態のまま残る場合がありますが、通常、プロセスが消滅する前にタスクは待機から復帰し、終了可能なパスに到達する必要があります。シグナルを繰り返すよりも、デバイス、マウント、ネットワーク、またはドライバの待機を修復することの方が重要であることが多いです。ホストの再起動が必要な場合は、データの整合性とサービスの冗長性を考慮して評価する必要があります。

フォローアップ 5: ロードアベレージのアラートはどのように設定すべきですか?

「負荷がCPU数を超える」という固定の閾値をそのままコピーしないでください。CPUバウンドなサービスの場合は、負荷、実行可能キュー、CPU PSI、使用率、およびcgroupのスロットリングを組み合わせます。I/Oヘビーなサービスの場合は、I/O PSI、D状態、デバイスまたはリモートストレージのレイテンシ、およびビジネスSLOを組み合わせます。通常のベースライン、継続時間、スケーリング所要時間、ユーザーへの影響に基づいて閾値を設定し、すべてのメトリクスのスコープを明記してください。

公開情報ソース

関連する質問