LinuxサーバーのCPU使用率が90%になる原因と、増強前に確認すべき項目

技術系
スポンサーリンク

CPU使用率が90%を超えてアラートが飛んでも、それだけではサーバーの容量不足とは判断できません。大事なのは「使用率・処理待ち・エラー」を同じ時系列で見て、実際に利用者への影響が出ているかを確認することです。この記事では、Linuxサーバーを1分間隔で監視していてCPU使用率90%のアラートが届いた僕が、増強を判断する前にどこを見ればいいかを整理します。サーバー監視をしていて「この数字、本当にヤバいの?」と不安になっている個人開発者・インフラ初心者向けです。

きっかけは、こんな監視結果でした。

メモリ使用率   :16.5%
スワップ使用率  :28.7%
CPU使用率    :92%
I/O待ち率    :0%
ロードアベレージ :5.59
/var ディスク使用率:67%
Apacheプロセス数 :371
Apache稼働状態  :active
HTTP応答コード  :200
レスポンスタイム :0.071秒

CPU使用率だけ見ると「スペック不足か…」と身構えるんですけど、よく見るとHTTP応答は200で、レスポンスタイムも0.071秒。つまり利用者はサクサク使えている状態なんですよね。この温度差をどう読むか、が今回のテーマです。

常時監視と定期監視は何が違うのか

「常時監視」と聞くと、1秒ごとにコマンドを叩き続けるようなイメージを持つかもしれません。でも実際のサーバー監視は、だいたい次のどれかです。

  • 監視エージェントを常駐させる方式
  • cronで一定間隔ごとに監視スクリプトを実行する方式
  • ログやサービス停止などのイベントを検知する方式

僕のように、cronで1分ごとに監視スクリプトを回している場合は、厳密には「定期監視」です。ただ、24時間ずっと状態を見ているという意味では、これで十分サーバー監視として成立しています。

よし、ここで一つ勘違いを外しておくと、大事なのは「1秒ごとに見る」ことじゃないんですよね。監視対象に合った間隔で、状態を継続的に記録できているかどうか。1分間隔でも、記録が続いていれば異常の兆しはちゃんと見えます。

CPU使用率90%だけでは容量不足と判断できない

CPU使用率が90%を超えると、反射的に「異常だ」と思いたくなります。でもCPUって、そもそも処理を実行するためのリソースなんですよね。アクセスやバッチ処理が一時的に増えれば、90%から100%近くまで上がること自体はごく普通に起きます。

今回の状態をもう一度切り出すと、こうでした。

CPU使用率   :92%
I/O待ち率   :0%
HTTP応答コード :200
レスポンスタイム:0.071秒

CPUは確かにたくさん使われている。でもWebサービスは正常に、しかも高速に応答している。これはつまり、サーバーが処理のためにCPUを使っているだけで、利用者への影響はまだ出ていないという状態かなと思います。CPU使用率が高いことと、サーバーの処理能力が足りないことは、イコールじゃないんですよね。ここを分けて考えるのが最初の一歩です。

一時的なCPU上昇と、継続的なリソース不足を分ける

たとえばCPU使用率がこんなふうに推移していたとします。

12:01 92%
12:02 30%
12:03 25%
12:04 35%
12:05 28%

一瞬90%を超えたけど、次の監視ではもう戻っている。こういうときは、一時的にこんな処理が走った可能性があります。

  • アクセス数の増加
  • 特定URL・APIへのアクセス集中
  • バッチ処理
  • バックアップ
  • ログ集計
  • ウイルススキャン
  • ApacheやPHPの一時的な処理

一方で、こんなふうに高いまま張り付いている場合は話が変わってきます。

12:01 92%
12:02 95%
12:03 94%
12:04 97%
12:05 91%

さらに、次のような現象が一緒に出ていたら、サーバーの処理能力不足を疑うサインです。

  • レスポンスタイムが悪化する
  • HTTP 500系エラーが増える
  • タイムアウトが発生する
  • Apacheの処理中ワーカーが上限に近づく
  • CPUの処理待ちが増える
  • バッチの完了時間が延びる

まとめると、見るべきはCPU使用率の「高さ」そのものじゃなくて、処理待ちやサービス影響が実際に出ているかなんですよね。単発の92%より、95%が5分続いていることの方がよっぽど怖い、という感覚です。

リソース不足は「3つの観点」で確認する

サーバーの状態を判断するときは、CPU使用率だけを見るのではなく、次の3つの観点をセットで確認すると迷いにくくなります。

使用率

リソースがどのくらい使われているか。

  • CPU使用率
  • メモリ使用量
  • ディスク使用率
  • Apacheワーカー使用率
  • DB接続数

処理待ち

処理しきれず、待ちが発生していないか。

  • CPUランキュー
  • ロードアベレージ
  • ApacheのBusyWorkers
  • ディスクI/O待ち
  • スワップイン・スワップアウト

エラー

利用者への影響や処理失敗が出ていないか。

  • HTTP 500系エラー
  • タイムアウト
  • 接続拒否
  • Apacheのワーカー上限到達
  • アプリケーションエラー

CPU使用率が90%でも、処理待ちもエラーもなくてレスポンスも正常なら、すぐに増強しなくてもいい可能性があります。逆に、使用率が中くらいでも処理待ちとエラーが出ていたら、そっちの方が優先度の高いサインです。

ロードアベレージはCPUコア数だけで判断しない

ロードアベレージは、実行中または実行待ちの処理数をざっくり把握するための指標です。CPUコア数との比較は目安のひとつになります。

たとえばロードアベレージが5.59だった場合、コア数によって見え方はけっこう変わります。

2コア :負荷が高い可能性がある
4コア :やや高い可能性がある
8コア :まだ処理できている可能性がある
16コア:大きな問題ではない可能性がある

コア数は次のコマンドで確認できます。

nproc

ただ、ここに落とし穴があって。ロードアベレージには「CPU待ち」だけじゃなく、割り込み不能なI/O待ちの状態も含まれるんですよね。だから、ロードアベレージがコア数を超えた = CPU不足とは言い切れません。I/Oが詰まっていて数字が膨らんでいるだけ、というケースもあります。

なので、vmstatのランキューやI/O待ちなど、他の値と組み合わせて判断します。

vmstat 1

主に見る列はこのあたりです。

r :CPUの実行待ち
si:スワップイン
so:スワップアウト
wa:I/O待ち

rが継続的にコア数を超えていれば「CPUの処理待ちが本当に発生している」と言えますし、waが高ければ原因はCPUじゃなくてディスク側かもしれない、という切り分けができます。

スワップ使用率は「今の入出力」を見る

今回の監視ではスワップ使用率が28.7%でした。数字だけ見ると「メモリ足りてないのでは」と思いがちですが、スワップ領域が使われているだけで、今まさにメモリ不足とは限らないんですよね。

Linuxでは、以前スワップに移された使用頻度の低いデータが、メモリに余裕が戻ってもそのまま置きっぱなしになることがあります。だからスワップ使用率そのものより、今スワップイン・スワップアウトが継続して起きているかの方が重要です。

vmstat 1

ここでsisoがずっと増え続けているなら、メモリ不足を疑います。逆に、メモリ使用率が低くてsisoもほぼ0なら、「昔の分が残っているだけ」で、そこまで慌てなくていい可能性が高いかなと思います。

Apacheプロセス数だけでは判断できない

今回の監視結果では、Apacheプロセス数が371でした。でも正直、371という数字だけでは異常かどうか判断できません。

判断するには、こういう情報がセットで要ります。

  • ApacheのMPMがprefork / worker / eventのどれか
  • MaxRequestWorkersの設定値
  • BusyWorkersの数
  • IdleWorkersの数
  • 通常時のプロセス数
  • 同時リクエスト数

たとえば371プロセスあっても、その大半が待機中(Idle)なら、直ちに問題とは限りません。一方で、こういう状態なら注意です。

MaxRequestWorkers:400
BusyWorkers   :380
IdleWorkers   :20

これは処理枠が上限にかなり近づいている状態です。単純なプロセス数より、BusyWorkersとMaxRequestWorkersの割合を見る方が、実態をつかみやすくなります。

なお、MPMや設定値の確認方法・デフォルト値は環境やディストリビューションによって異なるので、実際の値は自分のサーバー設定を確認してください。

CPU上昇とアクセス数を「同じ時刻」で並べる

CPU使用率の上昇が朝や昼に集中している場合、単純にアクセス数が増えているだけ、というのはよくあります。ただ、アクセスが増えたことと、サーバー容量が足りないことはまた別の話なんですよね。

たとえばこういう状態なら、アクセスをちゃんとさばけている可能性が高いです。

CPU使用率   :92%
リクエスト数  :増加
レスポンスタイム:0.1秒
5xxエラー件数 :0

一方、こうなっていたら、リソース不足かアプリのボトルネックを疑います。

CPU使用率   :95%
リクエスト数  :増加
レスポンスタイム:2.8秒
5xxエラー件数 :25件
BusyWorkers  :上限付近

だからこそ、CPU使用率とアクセス数を同じ時刻で記録するのが効いてきます。たとえばこんな記録があると、判断がぐっと楽になります。

時刻,CPU使用率,リクエスト数/分,平均応答時間,5xx件数
09:00,30,100,0.07,0
09:01,92,850,0.10,0
09:02,35,120,0.08,0
12:00,95,1200,2.80,25

09:01はCPUもアクセスも増えているけど、応答時間は正常で5xxもゼロ。これは「増えたけどさばけてる」状態。対して12:00は応答時間が悪化して5xxも出ている。こっちは処理能力不足か、特定処理がボトルネックになっている疑いが濃いです。

ちなみに、平均応答時間だけ見ていると、一部のすごく遅いリクエストが平均に埋もれて見えなくなることがあります。可能なら、平均に加えて次も見ておくと安心です。

  • 最大応答時間
  • 95パーセンタイル
  • 99パーセンタイル

Apacheのアクセス数をコマンドで確認する

Apacheを使っている場合、アクセスログからリクエスト数を確認できます。ログの場所は環境によりますが、一般的にはこのあたりです。

# Ubuntu / Debian系
/var/log/apache2/access.log

# RHEL / CentOS系
/var/log/httpd/access_log

たとえば、2026年7月10日12時31分台のアクセス数を数えるならこうです。

grep '10/Jul/2026:12:31' /var/log/apache2/access.log | wc -l

URL別に多い順で見たいとき。

grep '10/Jul/2026:12:31' /var/log/apache2/access.log |
awk '{print $7}' |
sort |
uniq -c |
sort -nr |
head -20

アクセス元IP別に見たいとき。

grep '10/Jul/2026:12:31' /var/log/apache2/access.log |
awk '{print $1}' |
sort |
uniq -c |
sort -nr |
head -20

これで、特定URLやIPからアクセスが集中していないかがわかります。

ただし注意点があって。毎分アクセスログ全体をgrepawkで読み直すのは、継続的な監視には向きません。ログが大きくなるほど、監視処理自体がCPUやディスクI/Oを食うようになるからです。スポット調査ならいいけど、常時監視の中に組み込むのは考えものかなと。

CPU使用率は /proc/stat の差分から取る

Linuxでは、CPUが使った時間の累積値を/proc/statから取れます。

cat /proc/stat

ただ、これを1回叩いただけでは使用率はわかりません。累積値なので、2つの時点を比べて初めて「その間どれだけ使ったか」が出ます。

前回のCPU累積値を保存
今回のCPU累積値を取得
全CPU時間の増分を計算
idle時間の増分を計算
差分からCPU使用率を算出

1分ごとに値を取って差分を計算すれば、基本的には直近1分間の平均CPU使用率が取れます。toppsを何度も起動するより、ずっと軽くCPU情報を取得できるのがポイントです。監視バッチに組み込むならこの方式がおすすめです。

Apacheの mod_status を利用する

Apacheのmod_statusが有効なら、状態を軽く取得できます。

curl -s http://127.0.0.1/server-status?auto

出力はこんな感じです。

Total Accesses: 1234567
Total kBytes: 987654
Uptime: 86400
ReqPerSec: 14.28
BusyWorkers: 24
IdleWorkers: 80

Total AccessesはApache起動後の累積リクエスト数です。前回値との差分を取れば、一定期間のリクエスト数がわかります。

12:00 Total Accesses 10000
12:01 Total Accesses 10600

1分間のリクエスト数:600

これなら、毎分アクセスログ全体を読み直さずに済みます。ログを舐めるより圧倒的に軽いんですよね。

ただし2つ気をつけたいことがあって。1つは、ReqPerSecは直近1分の値ではなく、一般的にはApache起動後からの平均値だという点。直近のアクセス数を知りたいならTotal Accessesの差分を使います。

もう1つは、Apacheを再起動するとTotal Accessesがリセットされること。たとえば前回値10万に対して今回値200、みたいに逆転すると、単純な差分がマイナスになってしまいます。なので監視側で、

今回値が前回値以上
→ 通常どおり差分を計算

今回値が前回値より小さい
→ Apache再起動・カウンターリセットとして扱う

という判定を入れておくと安全です。あとserver-statusは外部に公開せず、localhostか管理用ネットワークからだけアクセスできるよう制限してください。ここは環境ごとに設定が違うので、公式ドキュメントも確認しておくと安心です。

ログを使うなら「追記分だけ」読む

mod_statusが使えない場合は、アクセスログを毎回先頭から読み直すのではなく、前回以降に追記された分だけを読むようにします。

前回読み込んだファイル位置を保存
追加された行だけ取得
リクエスト数を集計
新しいファイル位置を保存

常駐処理でやるなら、追記分の監視はこれが手軽です。

tail -F /var/log/apache2/access.log

-Fを使うと、ログローテーション後も新しいファイルを追いかけてくれます。

監視バッチ自身の負荷を疑う

これ、意外と見落としがちなんですけど、監視処理そのものがCPU使用率を押し上げている可能性もあるんですよね。監視のためのバッチが重かったら本末転倒です。

現在の監視バッチがどれだけCPU・メモリを使っているかは、こう測れます。

/usr/bin/time -v /path/to/monitor.sh

主に見る項目はこのあたりです。

User time
System time
Elapsed time
Maximum resident set size
Percent of CPU this job got

毎分実行のバッチがこの程度なら、まず問題になりません。

実行時間:0.1秒
CPU時間 :0.02秒

でも、こんな感じだと監視方法の見直しが必要です。

実行時間 :20秒
CPU使用率:80%

さらに厄介なのが、スクリプトの処理順です。たとえばこんな構造になっていたとします。

巨大なアクセスログを集計
CPU負荷の高いコマンドを実行
最後にCPU使用率を取得

これだと、監視処理自身が生んだ負荷を「CPU高負荷」として記録してしまうんですよね。自作自演みたいな話で、地味にハマります(笑)。CPU使用率は重い集計の前に取るか、/proc/statの前回値との差分を使って、監視自身の影響がどれくらい混ざっているかを意識しておくといいです。

監視バッチの優先度を下げる

監視処理を低い優先度で回す手もあります。CPUの優先度を下げるならnice

nice -n 19 /path/to/monitor.sh

ディスクI/Oの優先度も下げるならioniceと組み合わせます。

ionice -c 3 nice -n 19 /path/to/monitor.sh

ただし勘違いしないでほしいのは、niceionice処理そのものを軽くするわけじゃないという点。あくまで他の処理より後回しにするだけです。毎分巨大なログを読み直すような重い処理があるなら、優先度をいじる前に監視方法そのものを見直す方が先かなと思います。

CPU使用率の単発値だけでアラートを出さない

1分ごとの監視で、CPU使用率が一度90%を超えただけでアラートを出すと、一時的な負荷でもいちいち通知が飛んできます。これ、しんどいんですよね。狼少年状態になって、そのうちアラートを無視するようになる。

なので、こういう条件にすると誤検知を減らせます。

警告:
直近5分の平均CPU使用率が85%以上

重大:
CPU使用率90%以上が5分継続
かつ、次のいずれかが発生

・レスポンスタイムが基準値を超えた
・5xxエラーが増えた
・BusyWorkersが上限に近づいた
・CPUランキューが継続的に増えた

CPU使用率だけで通知するとしても、単発値ではなく平均値や継続時間を使う方が実態に合います。

あと、異常が続いている間ずっと毎分同じアラートを送るのではなく、状態で管理するとだいぶ運用が楽になります。

異常を初めて検知
→ 初回通知

異常状態が継続
→ 通知を抑制、または一定時間後に継続通知

正常値に復帰
→ 復旧通知

サーバー増強を判断する前に記録しておく項目

まぁ結局のところ、増強するかどうかを決める前に、少なくとも次の情報を同じ時系列で記録しておくのが一番です。

CPU使用率
CPUコア数
CPUランキュー
ロードアベレージ
メモリAvailable
スワップイン・スワップアウト
I/O待ち率
Apache BusyWorkers
Apache IdleWorkers
MaxRequestWorkers
リクエスト数/分
平均応答時間
95パーセンタイル応答時間
5xxエラー件数
CPU使用率上位のプロセス

これらを並べると、こういう判断ができます。

アクセス数とCPU使用率が連動している

アクセス増加でCPUが上がっているだけの可能性。レスポンスが正常でエラーもなければ、すぐの増強は必要ないかもしれません。

CPU使用率だけが上がっている

バッチ・バックアップ・ログ集計・ウイルススキャンなど、アクセス以外の処理を疑います。

CPU使用率とレスポンスタイムが同時に悪化している

処理能力不足か、アプリのボトルネックの疑い。ここは本気で増強や改善を検討する場面です。

BusyWorkersが上限に近づいている

CPUではなく、Apacheの同時処理数や設定がボトルネックの可能性。設定見直しで済むこともあります。

アクセスが少ないのにCPUが高い

一部のURLやSQLが重い、異常なプロセスが動いている、あるいは監視バッチ自身が重い、といった線を疑います。

まとめ

CPU使用率が一時的に90%を超えても、それだけではサーバーの容量不足とは判断できません。見るべきは数字の高さより、こっちです。

  • CPU高負荷がどれだけ継続しているか
  • アクセス数とCPU使用率が連動しているか
  • CPUの処理待ちが発生しているか
  • レスポンスタイムが悪化していないか
  • 5xxエラーやタイムアウトが出ていないか
  • Apacheワーカーが上限に近づいていないか
  • 監視バッチ自身が負荷を生んでいないか

そして監視処理自体を軽くするには、毎分ログ全体を解析するのではなく、こういう方法が効きます。

  • CPUは/proc/statの累積値の差分から取る
  • Apacheはmod_statusTotal Accessesの差分を使う
  • ログを使うなら前回以降の追記分だけ読む
  • 監視バッチのCPU時間・実行時間を実測する
  • 必要に応じてniceioniceで優先度を下げる

サーバーの増強には毎月の費用がかかります。CPU使用率の単発値だけで飛びつくのではなく、アクセス数・処理待ち・レスポンス・エラーを同じ時系列で記録して、本当に利用者への影響が出ているかを確認してから判断する。これが遠回りなようで、いちばん確実かなと思います。

よくある質問

CPU使用率が90%を超えたらすぐサーバーを増強すべき?

単発の90%ではまだ判断できません。90%以上が数分継続していて、かつレスポンス悪化・5xxエラー・処理待ちの増加を伴っているかで見ます。応答が正常でエラーもなければ、増強を急がなくてよい場合が多いです。

ロードアベレージがCPUコア数を超えていたらCPU不足?

とは限りません。ロードアベレージにはI/O待ちも含まれるためです。vmstatr(CPU実行待ち)とwa(I/O待ち)を見て、CPU待ちが本当に発生しているのか、原因がディスク側なのかを切り分けてください。

スワップが使われていたらメモリ不足ですか?

使われているだけでは判断できません。過去にスワップへ移ったデータが残っているだけのこともあります。vmstatsi(スワップイン)とso(スワップアウト)が継続的に増えているかを確認し、増えているならメモリ不足を疑います。

監視はcronの1分間隔でも大丈夫?

多くの用途では十分です。大事なのは間隔の短さより、状態を継続的に記録できていること。ただし、毎分ログ全体を読むような重い処理を回すと監視自身が負荷になるので、/proc/statmod_statusの差分方式で軽く取るのがおすすめです。

アクセスは少ないのにCPUが高いのはなぜ?

一部のURLやSQLが重い、バッチやバックアップが動いている、異常なプロセスがいる、あるいは監視バッチ自身が重い、といった原因が考えられます。CPU使用率上位のプロセスを記録して、何が食っているのかを特定するのが近道です。

コメント

タイトルとURLをコピーしました