2026年10月13日
2026年10月13日
CPU負荷(ロードアベレージ)の監視とスロットリングの設定方法
CPU 負荷の監視は、ロードアベレージをコア数と比べて見るのが基本です。そのうえで、負荷が上がったときに重いバッチ処理を抑える(スロットリング)仕組みを用意しておくと、Web サイトの応答を守れます。この記事では、Linux サーバーで負荷を正しく読む方法、しきい値を超えたら通知するスクリプト、nice・systemd の CPUQuota・PHP-FPM の同時実行数による抑制方法を、WordPress サーバーを例に説明します。
ロードアベレージとCPU使用率は別物
uptime や /proc/loadavg で表示される3つの数字は、直近1分・5分・15分の平均的な「実行待ちのプロセス数」です。CPU 使用率(何%使っているか)とは意味が違います。
uptime
cat /proc/loadavg
nproc # 論理CPU数
読み方の目安は次のとおりです。
- ロードアベレージがコア数以下: 処理待ちはほぼ発生していません。
- コア数を継続して超える: CPU の取り合いが起きており、応答が遅くなり始めます。
- 1分値だけ高く15分値が低い: 一時的なスパイクです。cron の実行時刻などと照らし合わせます。
Linux のロードアベレージには、CPU を待つプロセスだけでなく、ディスク I/O の完了を待っている(D 状態の)プロセスも含まれます。そのため「ロードは高いのに CPU 使用率は低い」場合は、CPU ではなくディスクや NFS が詰まっている可能性が高いです。この切り分けを誤ると、CPU を増やしても改善しません。
内訳を確認するコマンド
vmstat 1 5 # r=実行待ち, b=I/O待ち, us/sy/id/wa/st を確認
mpstat -P ALL 1 3 # コアごとの使用率(sysstat パッケージ)
pidstat -u 1 5 # プロセスごとのCPU使用率(sysstat パッケージ)
vmstat の列は次のように読みます。
us(ユーザー処理)が高い: PHP や MySQL のクエリ処理など、アプリケーションが CPU を使っています。wa(I/O 待ち)が高い: ディスクが遅いか、スワップが発生しています。メモリ不足も疑います。st(steal)が高い: VPS やクラウドで、同じ物理ホストの他の利用者に CPU を取られています。自分のサーバー内では解決できないため、プランの変更や事業者への相談を検討します。
mpstat で1コアだけ使用率が上限近くに張り付いている場合は、シングルスレッドの処理(大きな SQL、画像変換など)がボトルネックです。全体の使用率が低く見えても、その処理は遅いままです。
負荷が高いときに通知するスクリプト
常設の監視ツール(Zabbix や Prometheus の node_exporter など)が無い小規模サーバーでは、cron で動く短いスクリプトでも十分役に立ちます。5分平均がコア数の 1.5 倍を超えたら、その時点の上位プロセスを添えてメールで知らせる例です。
#!/usr/bin/env bash
# /usr/local/bin/load-alert.sh
set -u
FACTOR="${LOAD_ALERT_FACTOR:-1.5}" # コア数の何倍で警告するか
MAIL_TO="${LOAD_ALERT_MAIL:-root}"
CORES=$(nproc)
read -r l1 l5 l15 _ < /proc/loadavg
limit=$(awk -v c="$CORES" -v f="$FACTOR" 'BEGIN { printf "%.2f", c * f }')
# 5分平均が limit 以上なら真
if awk -v a="$l5" -v b="$limit" 'BEGIN { exit !(a >= b) }'; then
# top の1回目の表示は値が不正確なことがあるため、2回目の画面を使う
detail=$(top -b -n 2 -d 2 | awk '/^top -/ { n++ } n == 2' | head -n 25)
logger -t load-alert "load1=$l1 load5=$l5 load15=$l15 limit=$limit"
printf 'load: %s %s %s (cores=%s, limit=%s)\n\n%s\n' \
"$l1" "$l5" "$l15" "$CORES" "$limit" "$detail" \
| mail -s "[load-alert] $(hostname)" "$MAIL_TO"
fi
# /etc/cron.d/load-alert
*/5 * * * * root /usr/bin/flock -n /run/load-alert.lock /usr/local/bin/load-alert.sh
ポイントは次の3つです。
- 5分値で判定する: 1分値はバックアップや cron 実行で簡単に跳ね上がるため、誤報が増えます。
- 通知に上位プロセスを含める: 通知を受けてからログインしたときには負荷が下がっていることが多く、その瞬間の情報が原因調査の手がかりになります。
- **シェルの
[ ]で比較しない**: ロードアベレージは小数なので、整数比較の-geは使えません。awkで比較しています。
負荷が高い状態が続くと5分ごとに通知が届くので、連続通知を抑えたい場合は状態ファイルで「通知済み」を記録する方法を組み合わせます。また、sar(sysstat)を有効にしておくと、過去の負荷を後から時系列で確認でき、「毎晩3時に上がる」といった傾向をつかめます。
スロットリングの方法
原因が分かったら、止められない処理は「遅くてもよいもの」と「遅れては困るもの」に分け、前者の優先度や上限を下げます。ここからの設定は本番に入れる前にステージング環境で試し、変更前の設定ファイルを控えておいてください。
nice / ionice で優先度を下げる
バックアップや画像の一括再生成のような重い処理は、優先度を下げて動かすだけで Web 側への影響が小さくなります。
nice -n 19 ionice -c3 /usr/local/bin/backup.sh
renice -n 10 -p 12345 # 動いているプロセスの優先度を下げる
nice は「CPU が空いていれば全力で使う」点に注意してください。CPU を他に使う処理が無ければ使用率は下がりません。上限を設けたい場合は次の CPUQuota を使います。ionice -c3(idle クラス)が効くかどうかは I/O スケジューラーに依存します。
systemd の CPUQuota で上限をかける
systemd 環境では、cgroup の機能で CPU 使用量に上限をかけられます。CPUQuota=50% は「1コア分の 50%」を意味し、複数コアを使わせたい場合は 200% のように書きます。
# 一度だけ上限付きで実行する
sudo systemd-run --scope -p CPUQuota=50% /usr/local/bin/backup.sh
# 常駐サービスに上限を設定する(ドロップインとして保存される)
sudo systemctl set-property myworker.service CPUQuota=100%
ユニットファイルに書く場合は [Service] セクションに CPUQuota= を追加し、systemctl daemon-reload してから再起動します。複数のサービスで CPU を分け合う比率を決めたいときは CPUWeight= を使います。これらは cgroup v2 環境を前提にしています(2026年10月現在、主要ディストリビューションの新しいリリースは cgroup v2 が既定です)。
注意したいのは、PHP-FPM や MySQL など Web の応答を担うサービスに厳しい CPUQuota をかけると、負荷は下がる代わりにすべてのリクエストが遅くなる点です。上限は「後回しにできる処理」にかけるのが原則です。
PHP-FPM の同時実行数を絞る
WordPress サーバーで CPU を使い切る典型は、PHP のプロセスが同時に大量に動く状態です。PHP-FPM のプール設定で pm.max_children を CPU とメモリに見合った数に抑えると、処理しきれないリクエストはキューで待つことになり、サーバー全体が共倒れになるのを防げます。
; /etc/php/8.3/fpm/pool.d/www.conf の例(パスはバージョンや OS で異なります)
pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500
値はサーバーの CPU 数と、1プロセスあたりのメモリ使用量から決めます。変更後は php-fpm -t(バイナリ名はディストリビューションによって php-fpm8.3 など)で構文を確認してから再読み込みします。
Web サーバー側でリクエストを抑える
特定の URL(wp-login.php や xmlrpc.php、検索ページなど)へのボットの集中が原因なら、PHP に届く前に Nginx の limit_req などで回数を制限するほうが効果的です。WordPress 側では、WP-Cron をアクセス時ではなくシステムの cron で実行するように切り替える(wp-config.php に define( 'DISABLE_WP_CRON', true ); を書き、cron から実行する)と、アクセスのたびに予定処理が走る負荷を避けられます。
負荷が上がったときの確認順
uptimeとnprocで、コア数に対してどの程度高いかを見る。vmstat 1でus・wa・stのどれが高いかを見て、CPU・I/O・ホスト側のどれかを切り分ける。topやpidstatで上位プロセスを特定する。PHP-FPM なら Web サーバーのアクセスログで、どの URL へのアクセスが増えているかを見る。- MySQL が上位ならスロークエリログを確認する。
- 原因に応じて、優先度の変更・上限設定・同時実行数・アクセス制限のどれで抑えるかを決める。
まとめ
- ロードアベレージは CPU 使用率ではなく実行待ちの数。コア数と比べ、5分値・15分値で判断する。
vmstatのus・wa・stで、CPU・ディスク・ホスト側のどれが原因かを切り分ける。- 通知スクリプトでは上位プロセスを一緒に記録しておくと原因調査が楽になる。
- 重い処理は
nice・ioniceで優先度を下げ、上限が必要なら systemd のCPUQuotaを使う。 - Web の応答を担うサービスは上限で縛らず、PHP-FPM の
pm.max_childrenや Nginx のlimit_reqで流入を調整する。