ブログ

CloudWatch メトリクス|EC2 の CPU 使用率は 1分統計だと合計も最大も同じ値になる

EC2 インスタンスの CPU 使用率を CloudWatch で確認するとき、統計に何を選ぶか迷ったことはないでしょうか。

マネジメントコンソールのグラフでは既定で平均が選ばれていますが、統計の選択肢には合計、最大、最小、サンプル数も並んでいます。 瞬間的な負荷の跳ね上がりを見逃したくないので最大を選んでおこう、という判断をされている方も多いと思います。

ところが EC2 の標準メトリクスについては、1分の期間で統計を取る限り、どれを選んでも返ってくる値は同じです。 CPU 使用率が 0% 付近のアイドル状態でも、全 vCPU を振り切ったフル負荷でも、1分の中で 0% と 100% を何度も往復させても変わりません。

今回は実際に EC2 インスタンスへ 3パターンの CPU 負荷をかけ、CloudWatch の統計がどのように返ってくるかを検証します。 あわせて、なぜ同じ値になるのか、どういう条件であれば統計を選ぶ意味が出てくるのかもご紹介します。

※ 本ブログの情報は 2026/09/09 時点の情報です。

CloudWatch メトリクス|統計は Period の中で何を計算しているのか

まず、CloudWatch の統計が何を計算しているのかを整理します。

統計は、指定した期間に集まったデータポイントを集計した結果です [*1]。 この期間のことを Period と呼び、統計を取得するときに秒数で指定します。

各統計の定義は次のとおりです。

  • SampleCount
     期間内のデータポイントの個数
  • Sum
     期間内の全データポイントの値を合計したもの
  • Average
     Sum を SampleCount で割ったもの
  • Minimum
     期間内で観測された最小の値
  • Maximum
     期間内で観測された最大の値

定義を並べると、ある事実が見えてきます。 期間内のデータポイントが 1個しかない場合、Sum はその値そのもの、Average も同じ値を 1で割った値、最小値も最大値もその値しかないため、すべて同じ結果になります。 そして SampleCount は 1になります。

つまり「統計を選ぶ意味があるかどうか」は、統計の種類ではなく、期間内にデータポイントが何個入るかで決まります。

【CPU 使用率の合計に意味はあるか】

余談ですが、AWS 公式のメトリクス一覧では、CPUUtilization の意味のある統計として Average、Minimum、Maximum の 3つだけが挙げられており、Sum は含まれていません [*2]。 CPU 使用率の単位はパーセントなので、異なる時点の使用率を足し合わせても物理的な意味を持たないためです。

一方で同じ EC2 のメトリクスでも、DiskReadOps のような回数を数えるメトリクスには Sum が挙げられています。 統計の使い分けは、まずメトリクスの単位から考えるとよさそうです。

【今回の予想】

詳細モニタリングを有効にした EC2 インスタンスは、1分間隔でメトリクスを送信します。 そうすると Period を 60秒にしたとき、その期間に入るデータポイントは 1個だけになるはずです。 CPU 使用率がどれだけ激しく上下していても、送信されるのは 1分あたり 1個なので、統計はすべて同じ値になると予想できます。

この予想が正しいか、実際に負荷をかけて確かめていきます。

CloudWatch メトリクス|検証環境と CPU 負荷のかけ方

検証には次の環境を使用しました。

  • インスタンスタイプ
     t3.medium(2 vCPU)
  • OS
     Amazon Linux 2023
  • リージョン
     東京(ap-northeast-1)
  • モニタリング
     詳細モニタリング(1分間隔)を有効化

【詳細モニタリングを有効化する】

EC2 のモニタリングには基本モニタリングと詳細モニタリングの 2種類があります [*3]。 既定は基本モニタリングで、この場合メトリクスは 5分間隔になります。 1分間隔のメトリクスが必要な場合は、詳細モニタリングを有効化します。

有効化は AWS CLI であれば次のコマンドです。

$ aws ec2 monitor-instances --instance-ids i-xxxxxxxxxxxxxxxxx
{
    "InstanceMonitorings": [
        {
            "InstanceId": "i-xxxxxxxxxxxxxxxxx",
            "Monitoring": {
                "State": "pending"
            }
        }
    ]
}

ここで一つ注意点があります。 詳細モニタリングは無料ではなく、送信されるメトリクスの数に応じた課金が発生します [*3]。 検証で有効化した場合は、終わったら忘れずに無効化してください。

【CPU 負荷は yes コマンドで作る】

CPU に負荷をかけるツールとしては stress-ng が有名ですが、今回は追加インストールをせずに済ませたかったため、標準で入っている yes コマンドを使いました。

yes は延々と文字列を出力し続けるコマンドで、出力を捨てながら実行すると 1プロセスで 1コアを使い切ります。 今回のインスタンスは 2 vCPU なので、2プロセス起動すれば CPU 使用率は 100% に張り付きます。

$ yes > /dev/null &
$ yes > /dev/null &

【3パターンの負荷を順番にかける】

CPU 使用率の状況によって結果が変わらないことを確認したいので、次の 3パターンを順番に流しました。

  • パターン1:アイドル(7分間)
     何も実行せず、CPU 使用率が 0% 付近の状態
  • パターン2:フル負荷(6分間)
     yes を 2プロセス起動し、CPU 使用率を 100% に張り付かせた状態
  • パターン3:激しい変動(6分間)
     10秒間フル負荷、10秒間アイドルを繰り返した状態

パターン3が今回の検証の肝になります。 1分の中で使用率が 0% と 100% を 3往復するため、もし CloudWatch が 1分の中の細かい変動を記録しているのであれば、Maximum と Minimum に大きな差が出るはずです。

負荷の投入には AWS Systems Manager の Run Command を使用しました。 インスタンスへ SSH でログインする必要がなく、実行内容がコマンド履歴として残るため、検証作業との相性がよいです。

$ aws ssm send-command \
    --instance-ids i-xxxxxxxxxxxxxxxxx \
    --document-name "AWS-RunShellScript" \
    --parameters file://load-params.json

パラメータファイルの内容は次のとおりです。 パターン1からパターン3までを 1つのスクリプトとして流し込み、各フェーズの開始時刻を記録するようにしています。

{
  "commands": [
    "echo \"PHASE1_IDLE_START $(date -u +%Y-%m-%dT%H:%M:%SZ)\"",
    "sleep 420",
    "echo \"PHASE2_FULL_START $(date -u +%Y-%m-%dT%H:%M:%SZ)\"",
    "yes > /dev/null &",
    "yes > /dev/null &",
    "sleep 360",
    "pkill -x yes",
    "echo \"PHASE3_FLUX_START $(date -u +%Y-%m-%dT%H:%M:%SZ)\"",
    "END=$(( $(date +%s) + 360 ))",
    "while [ $(date +%s) -lt $END ]; do yes > /dev/null & yes > /dev/null & sleep 10; pkill -x yes; sleep 10; done",
    "pkill -x yes || true",
    "echo \"ALL_DONE $(date -u +%Y-%m-%dT%H:%M:%SZ)\""
  ]
}

CloudWatch メトリクス|CPU 使用率を 3パターン変えて 1分統計を取得する

負荷が流れ終わったところで、CloudWatch から統計を取得します。 統計は 1回のコマンドで複数指定できるため、Sum、Average、Maximum、Minimum、SampleCount をまとめて要求しました。

$ aws cloudwatch get-metric-statistics \
    --namespace AWS/EC2 \
    --metric-name CPUUtilization \
    --dimensions Name=InstanceId,Value=i-xxxxxxxxxxxxxxxxx \
    --start-time 2026-09-09T05:48:00Z \
    --end-time 2026-09-09T06:14:00Z \
    --period 60 \
    --statistics Sum Average Maximum Minimum SampleCount

取得できた 24個のデータポイントから、各パターンの代表的なものを抜き出したものが次の表です。 時刻は日本時間で表記しています。

時刻負荷の状態SampleCountSumAverageMaximumMinimum
14:52アイドル10.190.190.190.19
14:56アイドル10.180.180.180.18
15:01フル負荷199.9999.9999.9999.99
15:03フル負荷1100.00100.00100.00100.00
15:06激しい変動150.0550.0550.0550.05
15:07激しい変動150.1650.1650.1650.16
15:08激しい変動150.0750.0750.0750.07

CPU 使用率が 0.18% のアイドル状態でも、100% に張り付いたフル負荷でも、4つの統計はすべて同じ値を返しました。 そして SampleCount はどの行も 1です。 取得した 24個すべてが同じ結果で、例外はありませんでした。

【表示の丸めではないことを確認する】

表の値は見やすさのために小数第 2位で丸めていますが、丸めたから同じに見えているわけではありません。 変動パターンの 1分間だけを取り出した生の出力が次のものです。

$ aws cloudwatch get-metric-statistics \
    --namespace AWS/EC2 --metric-name CPUUtilization \
    --dimensions Name=InstanceId,Value=i-xxxxxxxxxxxxxxxxx \
    --start-time 2026-09-09T06:07:00Z --end-time 2026-09-09T06:08:00Z \
    --period 60 --statistics Sum Average Maximum Minimum SampleCount

{
    "Label": "CPUUtilization",
    "Datapoints": [
        {
            "Timestamp": "2026-09-09T15:07:00+09:00",
            "SampleCount": 1.0,
            "Average": 50.15833333333334,
            "Sum": 50.15833333333334,
            "Minimum": 50.15833333333334,
            "Maximum": 50.15833333333334,
            "Unit": "Percent"
        }
    ]
}

小数第 14位まで完全に一致しています。

【最大値を選んでもスパイクは見えない】

ここで注目していただきたいのが、変動パターンの結果です。 この 1分間、インスタンスの中では 10秒ごとに CPU 使用率が 0% と 100% を往復していました。 1分の中で 3往復している計算になります。

それにもかかわらず、Maximum は 50.16% でした。 100% に達した瞬間が確かに存在したのに、最大値としては記録されていません。 同様に Minimum も 50.16% で、0% 付近まで落ちた瞬間も残っていません。

CloudWatch に届いたのは「この 1分の CPU 使用率は 50.16% でした」という 1個の値だけで、その 1分の中でどう動いたかという情報は最初から含まれていないためです。 統計の選び方の問題ではなく、記録されているデータの粒度の問題ということになります。

負荷が実際にかかっていたことは、インスタンス側でも確認しています。 フル負荷の最中に取得した状態が次のものです。

$ cat /proc/loadavg
2.04 1.12 0.46 3/142 2820

$ top -bn1 | head -3 | tail -1
%Cpu(s): 52.9 us, 47.1 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

アイドル率が 0.0% になっており、2 vCPU を使い切っている状態でした。

CloudWatch メトリクス|Period を 5分にすると統計は別々の値になる

では統計を選ぶ意味はまったく無いのかというと、そうではありません。 先ほどと完全に同じデータに対して、Period だけを 300秒に変えて取得してみます。

$ aws cloudwatch get-metric-statistics \
    --namespace AWS/EC2 \
    --metric-name CPUUtilization \
    --dimensions Name=InstanceId,Value=i-xxxxxxxxxxxxxxxxx \
    --start-time 2026-09-09T05:50:00Z \
    --end-time 2026-09-09T06:15:00Z \
    --period 300 \
    --statistics Sum Average Maximum Minimum SampleCount

結果は次のとおりです。

時刻SampleCountSumAverageMaximumMinimum
14:5051.220.240.380.18
14:555174.8534.9799.990.18
15:005465.7293.14100.0066.60
15:055249.8049.9650.2349.29
15:10511.422.2810.450.19

同じデータであるにもかかわらず、今度は 4つの統計がすべて違う値になりました。 SampleCount が 5になっていることが理由です。 5分の期間には 1分刻みのデータポイントが 5個入るため、その 5個に対して合計や最大が計算されるようになりました。

特にわかりやすいのが 14:55 の行です。 この 5分間はアイドル状態からフル負荷へ切り替わったタイミングを含んでおり、Maximum が 99.99%、Minimum が 0.18% と大きく開いています。 平均だけを見ていると 34.97% という中途半端な値ですが、Maximum を見れば「この 5分間のどこかで 100% に達した」ことがわかります。

つまり Maximum で負荷の跳ね上がりを捉えるという考え方は、Period がメトリクスの送信間隔より大きいときに初めて成立します。 逆に Period を送信間隔と同じ 1分まで縮めると、期間内のデータポイントが 1個になるため、Maximum は平均値と同じものを指すようになります。

【グラフの期間を短くすると情報が減ることがある】

この性質は、マネジメントコンソールでグラフを見るときにも影響します。次の 2枚は、今回の検証データを CloudWatch のグラフで描画したものです。

CloudWatch で CPUUtilization を Period 1分、統計 Average と Maximum で描画したグラフ

同じ期間を Period 5分、統計 Average と Maximum で描画したグラフ

Period を 1分にした上のグラフでは、Average(青)と Maximum(赤)の 2本を指定しているにもかかわらず、線が完全に重なって赤の 1本しか見えません。 同じ時間帯を Period 5分で描画した下のグラフでは、アイドルからフル負荷へ切り替わった 14:55 の期間で Maximum だけが 100% 付近まで立ち上がり、2本の線が分かれます。

CloudWatch ダッシュボードの Period override を Auto にしている場合、グラフの Period は時間範囲に合わせて自動で調整されます [*6]。 時間範囲が 1日以下なら設定した Period がそのまま使われ、1日を超えると 5分未満の Period は 5分に、3日を超えると 1時間未満の Period は 1時間に引き上げられます。 そのため、時間範囲を 1日以下に狭めて Period が 1分のまま表示されていると、Maximum を選んでも Average と同じ線になり、5分表示のときには見えていた変動幅が見えなくなります。

Sum についても同様で、CPU 使用率のような割合を表すメトリクスでは、5分の期間で 465.72 という値が返ってきても解釈のしようがありません。 公式ドキュメントが CPUUtilization の意味のある統計から Sum を外している理由がここにも表れています。

CloudWatch メトリクス|基本モニタリングでは Period 60 を指定しても 1分にならない

最後に、詳細モニタリングを有効化する前のデータも見ておきます。 今回のインスタンスは検証の直前まで基本モニタリング、つまり 5分間隔の状態で動いていました。

その期間に対して、あえて Period を 60秒にして取得した結果が次のものです。

時刻SampleCountSumAverageMaximumMinimum
14:3510.0040.0040.0040.004
14:4054.870.973.770.17
14:4551.240.250.300.18

Period には 60秒を指定しているのに、返ってきたデータポイントの時刻は 5分刻みで、しかも SampleCount が 5になっています。 1分ごとのデータが返ってくることを期待していると、この結果は意外に感じられるかもしれません。

理由は EC2 がメトリクスを送信する仕組みにあります。 EC2 は基本モニタリングの状態でも 60秒ごとに値をサンプリングしており、その 5個分をまとめて 5分周期で CloudWatch に送信しています [*5]。 このとき送られるのは 1個の代表値ではなく、最小値、最大値、合計、サンプル数をひとまとめにした形式で、CloudWatch ではこれを統計セットと呼びます [*4]。

そのため 5分刻みのタイムスタンプに 5個分の情報が入った状態になり、Period を 60秒まで縮めても分解できません。 一方で、統計セットの中には最小値と最大値が保持されているため、14:40 の行では Maximum が 3.77%、Minimum が 0.17% と差が出ています。

【粒度を上げると変動幅が見えなくなるという逆転】

ここまでの結果を並べると、少し面白いことが起きています。

  • 基本モニタリング(5分間隔)
     Period 60 でも 300 でも SampleCount は 5
     → 5分間の中の 1分ごとの最大値・最小値がわかる
  • 詳細モニタリング(1分間隔)
     Period 60 では SampleCount が 1
     → 1分間の中の変動は一切わからない
  • 詳細モニタリングを有効にすると時間方向の解像度は 5倍になりますが、1分のバケットで見る限り、その中の変動幅を示す情報は無くなります。 変動幅も知りたい場合は、詳細モニタリングのまま Period を 300秒にして取得すれば、1分ごとの値に対する最大値と最小値が得られます。

    監視の設計を考えるときは、送信間隔と Period の両方を意識しておくと、意図した情報が取れているかを判断しやすくなります。

    CloudWatch メトリクス(まとめ)

    いかがでしたでしょうか?

    本ブログでは、EC2 の標準メトリクスにおいて、1分の期間で統計を取得すると合計、平均、最大、最小がすべて同じ値になることを検証しました。 詳細モニタリングを有効にした EC2 は 1分あたり 1個のデータポイントしか送信しないため、その期間を集計しても対象が 1個しかない、というのが理由になります。 CPU 使用率をアイドルからフル負荷まで変えても、1分の中で 0% と 100% を往復させても、結果は変わりませんでした。

    実務で押さえておきたいのは、1分未満の負荷の跳ね上がりは統計の選び方では捉えられないという点です。 最大値を選べばスパイクが見えるという考え方が成り立つのは、Period がメトリクスの送信間隔より大きいときに限られます。

    とはいえ、秒単位の負荷変動まで追いたい場面もあるかと思います。 その場合は CloudWatch エージェントから高解像度のカスタムメトリクスを送信する方法がありますが、送信するデータポイントの数だけ費用がかかるため、どこまでの粒度が本当に必要かを整理してから設計することをおすすめします。

    今回ご紹介した CloudWatch の監視設計をはじめ、ターン・アンド・フロンティアでは AWS をご利用されているお客様に技術的なご支援が可能ですので、CloudWatch の活用にご興味のある方は お問い合わせフォーム よりお気軽にご相談ください。

    CloudWatch メトリクス(ご参考)

    *1「CloudWatch 統計の定義」 https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/Statistics-definitions.html

    *2「インスタンスで使用できる CloudWatch メトリクス」 https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/viewing_metrics_with_cloudwatch.html

    *3「EC2 インスタンスの詳細モニタリングを管理する」 https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/manage-detailed-monitoring.html

    *4「Amazon CloudWatch の概念」 https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html

    *5「Why does my Amazon EC2 instance exceed its network limits when my average utilization is low?」 https://repost.aws/knowledge-center/ec2-instance-exceeding-network-limits

    *6「CloudWatch ダッシュボードの期間の上書き設定または更新間隔の変更」 https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/change_dashboard_refresh_interval.html

    【筆者実行環境】 PC:Mac(Apple Silicon) OS:macOS 26.6.2 aws cli:aws-cli/2.35.14 検証対象インスタンス:t3.medium(Amazon Linux 2023) SSM Agent:3.3.4624.0

元記事発行日: 2026年10月05日、最終更新日: 2026年09月15日