LinuxでCPU負荷が高い原因を特定する方法

LinuxでCPU負荷が高い原因を特定する方法

LinuxでCPU負荷が高い状態に遭遇したとき、最初にやるべきことは「CPU使用率が高い」という結果だけで判断しないこと。実際には、CPUを本当に使い切っているのか、特定のプロセスだけが暴れているのか、ロードアベレージが高いだけでI/O待ちが混ざっているのか、あるいは短時間のスパイクなのかで対処が変わる。原因特定を速くするには、top、ps、pidstat、mpstat、sar、perf などを役割ごとに使い分けて、「全体」「CPU単位」「プロセス単位」「時系列」「関数レベル」に分解して見るのが基本になる。

最初に見るべきものを整理する

CPU負荷の切り分けでは、次の順で考えると整理しやすい。
・本当にCPUが詰まっているのか
・どのプロセスが高負荷なのか
・全CPUが均等に高いのか、一部だけ偏っているのか
・一時的なスパイクか、継続的な高負荷か
・アプリ処理か、暗号化、圧縮、DB、ログ、監視ツールなど別要因か
CPUだけ見て原因を断定すると、実際にはI/O待ちやメモリ不足が根本なのに、誤ってアプリコードだけを疑ってしまうことがある。

まずは top で全体像を把握する

最初の一手としては top が最も手早い。
リアルタイムで、
・load average
・CPU使用率
・メモリ使用量
・上位プロセス
を同時に見られる。

top

見るポイントは、
%Cpu(s) の user / system / idle
・上位プロセスの %CPU
・load average の推移
・CPU使用率が高いのに idle が残っていないか
ここで「どのプロセスが高いか」「システム全体が詰まっているか」をまず分ける。

ロードアベレージとCPU使用率を混同しない

ロードアベレージはCPU使用率そのものではない。
短く言えば、CPU実行待ちやブロック待ちを含む“負荷の平均”として見る方が分かりやすい。
確認は次でできる。

uptime

または、

cat /proc/loadavg

ここでありがちな勘違いは、
・load average が高い = CPU100% と決めつける
・1分値だけ見て騒ぐ
・CPUコア数を無視して数字だけ見る
というもの。
たとえば多コア環境では、同じロードアベレージでも意味が変わるため、CPU数と合わせて考える必要がある。

CPUを使っているプロセスを ps で一覧化する

top でおおまかな犯人候補を見つけたら、次は一覧で整理する。
CPU使用率が高い順に並べるなら次が分かりやすい。

ps aux –sort=-%cpu | head

これで、どのプロセスがCPUを食っているかをすぐに見つけやすい。
たとえば、
・php-fpm
・java
・python
・node
・mysqld
などが上位に来ていれば、そのプロセスの中身を掘る方向へ進める。
一方で、プロセスが頻繁に入れ替わる場合は、短時間のジョブやcronが原因のこともある。

プロセス単位のCPU推移は pidstat が見やすい

瞬間値ではなく、「どのプロセスが継続的にCPUを使っているか」を見るなら pidstat が便利。
特定プロセスのCPU使用状況や全体の活動中タスクを間隔付きで見られる。

pidstat 1

特定PIDだけ見たいなら次のようにする。

pidstat -p 1234 1

これにより、
・常に高いのか
・一定間隔で跳ねるのか
・複数ワーカーが分散して高いのか
が見やすくなる。
短いスパイクが原因なら、pstop の一回表示だけでは見逃しやすい。

CPUごとの偏りは mpstat で確認する

CPU負荷が高いとき、全コア均等に重いのか、一部CPUだけが高いのかで見方が変わる。
CPUごとの偏りを見るなら mpstat が役立つ。

mpstat -P ALL 1

これで全CPUごとの使用率を確認できる。
たとえば、
・1コアだけ極端に高い
・特定のCPUに偏っている
・全体的に満遍なく高い
といった違いを見つけやすい。
シングルスレッド処理や、特定ワーカーが1CPUへ張り付く問題はここで見えやすい。

user と system の比率で方向を分ける

CPU負荷が高いときは、「何にCPUが使われているか」を user / system の比率で見ると方向性が分かりやすい。
top や mpstat の %usr%sys を見る。
ざっくりした見方としては、
・user が高い → アプリ計算、圧縮、暗号化、変換処理、ループ
・system が高い → カーネル側処理、I/O関連、ネットワーク、システムコール多発
この切り分けだけでも、「アプリコードを掘るべきか」「OS寄りの問題を疑うべきか」がかなり整理しやすい。

継続的な傾向は sar で見る

「今この瞬間」だけでなく、時間帯による傾向を見るなら sar が便利。
特に「毎日同じ時間に重い」「夜間バッチの時間だけCPUが跳ねる」といった問題では、時系列が重要になる。

sar -u 1 5

CPU全体の履歴確認では、sysstatの収集設定が入っていれば過去分も追いやすい。
これにより、
・一時的な高負荷か
・周期的な負荷か
・継続的な高負荷か
を分けやすい。
瞬間値だけを見て原因を探すより、再現パターンが見える方が対策しやすい。

高負荷プロセスの正体を細かく掘る

CPUを使っているプロセスが分かったら、そのプロセスが何をしているかを掘る。
たとえばPIDが分かっているなら、詳細は次で見やすい。

ps -fp 1234

子プロセスやスレッドも含めて見るなら、topのスレッド表示や ps -L も使える。
マルチスレッドアプリでは、
・1スレッドだけが高負荷
・ワーカー全体が均等に高負荷
・親プロセスではなく子だけ重い
という違いがあるため、プロセス名だけで判断しない方が良い。

関数レベルまで掘るなら perf を使う

アプリやプロセスがCPUを食っているのは分かったが、「どの関数やどの処理で詰まっているか」まで見たい場合は perf が強い。
システム全体をリアルタイムで見るなら次のような使い方がある。

sudo perf top

特定コマンドの計測には perf stat が使える。

sudo perf stat python script.py

記録して後で見るなら次の流れ。

sudo perf record -p 1234
sudo perf report

これにより、CPUを使っている関数やシンボル単位で傾向を見やすくなる。
「重いのは分かるが、コードのどこか分からない」段階から一段深く入れる。

CPU負荷の原因がアプリ外にあることも多い

CPUが高い原因は、必ずしもアプリ本体とは限らない。
実際によくあるのは次のようなもの。
・ログの圧縮
・バックアップ
・ウイルススキャン
・監視エージェント
・メトリクス収集
・暗号化処理
・cronジョブ
・CI/CDのビルド
そのため、アプリプロセスだけでなく、システム全体のプロセス一覧を見ることが重要になる。
「Webが重いからWebアプリが原因」と決めつけると見誤りやすい。

CPUだけでなくメモリとI/Oも一緒に見る

CPU負荷が高いように見えても、実際にはメモリ不足やI/O待ちから副次的に遅くなっていることがある。
最低限、次は合わせて見る方が良い。

free -h
vmstat 1

たとえば、
・swapが増えている
・I/O待ちが高い
・CPU使用率よりロードアベレージが不自然に高い
といった場合は、CPU以外が根本原因のことがある。
CPU負荷調査は、CPUだけで閉じない方が正確になりやすい。

ログと時間帯を組み合わせると原因を絞りやすい

高負荷が起きた時間帯に、
・アプリログ
・Webサーバーログ
・バッチ実行ログ
・cron
を重ねると、原因がかなり絞れることがある。
たとえば、毎日2時だけCPUが上がるなら、cronやバックアップの可能性が高い。
リクエスト急増と一致するなら、アクセス集中や特定APIの重さが疑いやすい。
OSの数値だけでなく、アプリ側の時系列も合わせて見ることが重要になる。

よくある失敗と勘違い

CPU負荷の切り分けでよくある失敗はかなり典型的。
・topを一瞬見ただけで原因を決める
・load average をCPU%だと思う
・短期スパイクを見逃す
・systemが高いのにアプリコードだけ疑う
・高負荷プロセスを見つけたが、その親子関係を見ていない
・CPUだけ見て、実はI/O待ちやswapを見ていない
特に、瞬間値と継続傾向を分けて見ないと、再現条件の把握が難しくなりやすい。

初動で使いやすいコマンド順

CPU負荷が高いときに、実際に使いやすい順番は次の流れ。

  1. top で全体を見る
  2. ps aux --sort=-%cpu | head で上位プロセスを確認
  3. pidstat 1 で継続的な高負荷タスクを見る
  4. mpstat -P ALL 1 でCPUごとの偏りを見る
  5. free -hvmstat 1 でメモリ・I/Oを確認
  6. 必要なら perf topperf record で掘る
    この順で進めると、「全体 → プロセス → CPU単位 → 深掘り」という流れが作りやすい。

まとめ

LinuxでCPU負荷が高い原因を特定するには、
top で全体像を見る
pspidstat で高負荷プロセスを特定する
mpstat でCPUごとの偏りを見る
sar で時系列傾向を見る
perf で必要なら関数レベルまで掘る
・メモリ、swap、I/Oも合わせて確認する
という流れがかなり有効になる。
重要なのは、「CPUが高い」という結果だけで判断せず、
・何が
・いつ
・どのくらい
・どの層で
重いのかを段階的に絞ること。
この順番で見るだけでも、原因特定の速度はかなり変わりやすい。