EC2 Linux で CPU・メモリ高騰時の原因プロセスを特定してみた
はじめに
クラスメソッドオペレーションズの Shimizu です。
弊社サポートデスクに「EC2 サーバーのCPU・メモリ使用率が高騰していたので、原因を調べてほしい」というお問い合わせをよくいただきます。
しかしながら、これらの原因は「発生当時の OS 内部のプロセス状況」を記録していなければ、あとから調べることは難しいものになります。
Linux OS にログインして ps コマンド等を実行することで「その時点のプロセス状況」を確認できますが「CPU・メモリが高騰していた当時のプロセス状況」をさかのぼって調べることはできません。
また CloudWatch のカスタムメトリクスを設定することで当時のCPU・メモリ使用率全体の増減は確認できますが、その原因となった OS 上のプロセスまでは特定できません。
そこで今回は Linux OS の一般的なコマンド sysstat を使用して、CPU・メモリが高騰していた当時のプロセス状況を記録し、あとから原因を調べてみました。
以下に、その詳しい手順をご紹介します。
やってみた
今回は Amazon Linux 2023 の EC2 インスタンスでプロセスごとのメモリ使用率をログに記録し、意図的に負荷をかけて、ログから原因プロセスを特定する、という検証をやってみました。
他の一般的な Linux ディストリビューション(RHEL 系や Ubuntu 等)でも sysstat コマンドが入っていれば、同様の手順が可能です。
事前準備(sysstat、pidstat の確認)
まず対象 EC2 にログインして sysstat パッケージ(sar)が入っているかを確認し、必要に応じてインストールします。
# sysstatパッケージ(sar)のバージョン確認
$ sar -V
# 出力例
sysstat version 12.5.6
(C) Sebastien Godard (sysstat <at> orange.fr)
# まだ 入っていない場合はインストールする
$ sudo dnf install sysstat
sysstat パッケージの導入を確認できたら、次は pidstat コマンドを実行して、プロセスごとの CPU・メモリ使用率を確認してみます。
# まずはオプション無しで実行
$ pidstat
# 出力例(プロセスごとのCPU使用率が表示される)
03:45:13 UID PID %usr %system %guest %wait %CPU CPU Command
03:45:13 0 1 0.02 0.02 0.00 0.01 0.04 1 systemd
03:45:13 0 872 0.01 0.00 0.00 0.01 0.01 1 systemd-journal
03:45:13 0 1341 0.00 0.00 0.00 0.00 0.00 0 auditd
# -r オプションで実行
$ pidstat -r
# 出力例(プロセスごとのメモリ使用率が表示される)
03:17:22 UID PID minflt/s majflt/s VSZ RSS %MEM Command
03:17:22 0 1 25.54 0.22 107668 17840 0.45 systemd
03:17:22 0 872 5.91 0.17 52216 22348 0.57 systemd-journal
03:17:22 0 1341 0.08 0.00 21920 2372 0.06 auditd
pidstat コマンドでプロセスごとのCPU/メモリ使用率を取得できましたが、これはコマンドを実行した瞬間のみの情報です。
CPU・メモリが高騰した当時の状況を追えるように、次の手順ではこのコマンド結果をログに記録していきます。
ログの取得(pidstat の連続実行)
OS 上にログ保存用の適当なフォルダを作成して、その中に pidstat コマンドを連続実行した結果をテキストファイルで出力します。
コマンドの実行間隔と記録回数はオプションで指定できます。
あまり長期間に設定するとログのファイルサイズが大きくなってしまうため、ここでは 5 秒間隔 x 24 回(= 2 分間)を記録してみます。調査したい対象に合わせて、コマンドの取得間隔や回数を適宜調整しましょう。
# ログ保存用の適当なフォルダを作成
$ mkdir ~/processlog
# CPU使用率をログに記録(2分間)
pidstat 5 24 > ~/processlog/cpu_$(date +%Y%m%d).log &
# メモリ使用率をログに記録(2分間)
pidstat -r 5 24 > ~/processlog/mem_$(date +%Y%m%d).log &
# 完了した時の出力例
[1]- Done pidstat 5 24 > ~/processlog/cpu_$(date +%Y%m%d).log
[2]+ Done pidstat -r 5 24 > ~/processlog/mem_$(date +%Y%m%d).log
なお今回はCPUとメモリの両方を記録していますが、どちらか一方のみでも OK です。
また出力例にあるように、ログには実行時の時刻が記録されるものの、日付は記録されません。そのため後から分かりやすいよう、記録するログファイル名に日付を入れておくことをおすすめします。
(任意)意図的にCPU・メモリ負荷をかける
ここではCPUとメモリの負荷増減をわかりやすくログに記録するため、stress-ng ツールで意図的に負荷をかけてみます。
# 負荷ツール stress-ng のインストール
sudo dnf install stress-ng
# CPU 2ワーカー + メモリ 1ワーカーで2GB を、60秒間占有する
stress-ng --cpu 2 --vm 1 --vm-bytes 2G --vm-keep --timeout 60s
# 完了した時の出力例
stress-ng: info: [116020] setting to a 60 second run per stressor
stress-ng: info: [116020] dispatching hogs: 2 cpu, 1 vm
stress-ng: info: [116020] successful run completed in 60.09s (1 min, 0.09 secs)
ここでは stress-ng ツールの詳しい説明を省きますが、もし実施する場合は以下のサイトを参考にしてみてください。
ログから原因プロセスを特定する
まずは前の手順で取得したCPUログとメモリログを、そのまま cat コマンドで見てみます。
# CPUログの表示
cat ./processlog/cpu_20260803.log
# 出力例
01:03:57 UID PID %usr %system %guest %wait %CPU CPU Command
01:04:02 0 1 0.20 0.00 0.00 0.00 0.20 1 systemd
01:04:02 0 1533 0.20 0.00 0.00 0.00 0.20 1 containerd
01:04:02 1001 115970 0.00 0.20 0.00 0.00 0.20 0 pidstat
01:04:02 UID PID %usr %system %guest %wait %CPU CPU Command
01:04:07 0 1533 0.00 0.20 0.00 0.00 0.20 1 containerd
01:04:07 1001 116021 33.20 0.00 0.00 17.20 33.20 0 stress-ng-cpu
01:04:07 1001 116024 4.20 26.80 0.00 19.60 31.00 1 stress-ng-vm
# メモリログの表示
cat ./processlog/mem_20260803.log
# 出力例
01:04:06 UID PID minflt/s majflt/s VSZ RSS %MEM Command
01:04:11 1001 115968 2.20 0.00 222312 3052 0.08 pidstat
01:04:11 1001 115970 2.20 0.00 222312 3056 0.08 pidstat
01:04:11 1001 116024 77766.00 0.20 2158360 2098400 53.37 stress-ng-vm
01:04:11 UID PID minflt/s majflt/s VSZ RSS %MEM Command
01:04:16 1001 116024 1.60 0.20 2158360 2098660 53.38 stress-ng-vm
このままでは連続実行されたコマンド結果がそのまま羅列されていて見づらいので、ログを整形して表示してみます。
下記例ではログ内のCPU・メモリ使用率を示す列(8列目 = -k7)の数値が大きい順にソートして5件まで表示する、というコマンドを実行しています。
# CPUログを整形して表示
grep -vE 'UID^$' ./processlog/cpu_20260803.log | sort -k7 -nr | head -5
# 出力例(stress-ng-cpu プロセスがCPUを 63% 以上占有していた期間がある)
01:04:32 1001 116022 60.80 0.00 0.00 39.20 60.80 0 stress-ng-cpu
01:04:57 1001 116022 62.80 0.00 0.00 37.20 62.80 1 stress-ng-cpu
01:04:42 1001 116024 61.40 1.40 0.00 37.20 62.80 0 stress-ng-vm
01:04:12 1001 116024 54.20 8.20 0.00 37.20 62.40 1 stress-ng-vm
01:04:37 1001 116021 63.20 0.20 0.00 36.60 63.40 1 stress-ng-cpu
# メモリログを整形して表示
grep -vE 'UID^$' ./processlog/mem_20260803.log | sort -k7 -nr | head -5
# 出力例(stress-ng-vm プロセスがメモリを 53% 以上占有していた期間がある)
01:04:51 1001 116024 0.00 0.20 2158360 2098660 53.38 stress-ng-vm
01:04:16 1001 116024 1.60 0.20 2158360 2098660 53.38 stress-ng-vm
01:04:11 1001 116024 77766.00 0.20 2158360 2098400 53.37 stress-ng-vm
01:04:06 1001 116024 131954.40 0.20 2158360 543176 13.82 stress-ng-vm
01:05:31 0 872 7.60 0.00 106404 56988 1.45 systemd-journal
この結果から、ログを記録していた期間中に最も多くCPU・メモリを占有していた原因プロセスが stress-ng であることを特定できました!
さいごに
いかがでしたでしょうか。
CPUやメモリ高騰の原因プロセスを特定したい場合、特別なツールの導入は不要で、一般的な Linux OS に搭載されている sysstat コマンドのみで実現できることをお伝えできたかと思います。
もし本番環境で利用する場合、CPUやメモリが高騰する時間帯にあらかじめ pidstat コマンドをスケジュール実行するスクリプトを設定しておけば、当該時刻のプロセス状況を後からさかのぼって調査することも可能になります。
今回は Linux OS について書きましたが、Windows OS の場合は異なる設定が必要なため、また機会があれば記事にしたいと思います。
この情報がどなたかのお役に立てば幸いです!
参考資料
- sar(1) - Linux manual page (man7.org)
- pidstat(1) - Linux manual page (man7.org)
- sar.sysstat(1) — sysstat — Debian Manpages
クラスメソッドオペレーションズ株式会社について
クラスメソッドグループのオペレーション企業です。
運用・保守開発・サポート・情シス・バックオフィスの専門チームが、IT・AIをフル活用した「しくみ」を通じて、お客様の業務代行から課題解決や高付加価値サービスまでを提供するエキスパート集団です。
当社は様々な職種でメンバーを募集しています。
「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、クラスメソッドオペレーションズ株式会社 コーポレートサイト をぜひご覧ください。
※2026年1月 アノテーション㈱から社名変更しました









