0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS EC2サイジング入門 CPU・メモリ・EBS・Compute Optimizerを見る

0
Last updated at Posted at 2026-08-27

AWS EC2サイジング入門 CPU・メモリ・EBS・Compute Optimizerを見るのアイキャッチ

はじめに

EC2のインスタンスタイプを選ぶとき、「とりあえずCPUとメモリが大きいもの」を選んでいないでしょうか。

EC2サイジングは、vCPUとメモリだけでは決められません。EBSのIOPSやスループット、EC2側のEBS帯域、ネットワーク、ピーク時間、バッチの完了時間も影響します。

この記事では、新規構築、既存EC2の見直し、オンプレミスからの移行で使える手順を、EBSも含めて具体的に説明します。

先に結論

EC2サイジングは、次の順番で進めます。

  1. 応答時間、処理量、バッチ完了時間などの要件を決める
  2. CPU、メモリ、ネットワーク、EBSの現状を測る
  3. 負荷の特徴からインスタンスファミリーを選ぶ
  4. ピークと成長分の余裕を加え、サイズを選ぶ
  5. EBSの容量、IOPS、スループットを別々に決める
  6. 負荷試験と本番メトリクスで再評価する

最初の選定を正解だと考えず、説明できる初期値を置き、測定して直すのがポイントです。

前提

  • 対象読者: EC2とEBSのサイジングを基礎から学びたい人
  • 対象環境: Amazon EC2、Amazon EBS、Amazon CloudWatch、AWS Compute Optimizer
  • OS例: Amazon Linux 2023
  • AWS CLI: AWS CLI v2
  • CLI出力の集計: jq
  • 扱わない範囲: GPU、HPC、SAP、Oracleライセンスの個別設計
  • 仕様確認日: 2026年8月27日

AWSのインスタンス世代、利用可能なサイズ、帯域、料金は更新されます。実際の設計では、対象リージョンのAWSコンソールと公式ドキュメントで再確認してください。

用語の短い説明

用語 説明
vCPU EC2から見える論理CPU。多くのインスタンスでCPUコアのスレッドに相当する
IOPS 1秒間に処理できる読み書き回数の目安
スループット 1秒間に転送できるデータ量の目安
レイテンシ 1回の処理やI/Oが完了するまでの待ち時間
P95 データの95%がその値以下に収まる境界
ライトサイジング 大きすぎる、または小さすぎるリソースを適切なサイズへ直すこと

1. 最初に性能要件を数値化する

サイジングの目的は、CPU使用率を下げることではありません。システムが必要な性能を満たし、運用とコストのバランスを取ることが目的です。

確認項目 質問の例
応答時間 Web APIのP95応答時間を1秒以内にするか
同時利用 通常時とピーク時の同時接続数はいくつか
処理量 1秒あたりのリクエスト数やファイル数はいくつか
バッチ 夜間バッチを何時までに終える必要があるか
成長率 6か月後、1年後に利用量はどれくらい増えるか
障害時 1台が停止したとき、残りの台数で処理できるか
ライセンス vCPU数、コア数、CPUメーカーによる制約があるか
変更可能時間 停止を伴うサイズ変更をいつ行えるか

「遅くないサーバー」では完了条件を判定できません。「ピーク200リクエスト/秒でP95応答時間1秒以内」のように数値化します。

2. 状況別に情報の集め方を変える

新規構築

実績値がないため、似たシステムの実績、想定リクエスト数、データ量から初期値を置き、負荷試験で確認します。Auto Scalingに対応できる構成なら、1台を過大にする方法と比較します。

既存EC2

CloudWatchとOS内のメトリクスを使います。平常日だけでなく、月末・月初、夜間バッチ、キャンペーン、リリース直後などの業務ピークを含めます。

取得日数に万能な正解はありません。少なくとも、定期処理と高負荷日が入る代表期間を取ります。

オンプレミスからの移行

オンプレの「8コア、32GBメモリ、1TBディスク」を、そのままEC2へ写しません。物理サーバーは数年先を見越して大きく購入していることがあるためです。

  • CPUの平均、P95、最大、コア別使用率
  • 利用可能メモリ、スワップ、OOMの有無
  • ディスク容量と増加率
  • 読み書きIOPS、転送量、レイテンシ、キュー
  • ネットワークの送受信量と接続数
  • ジョブの実行時間と締め切り
  • CPUコア数に連動するソフトウェアライセンス

AWS Application Migration Serviceは移行を支援しますが、移行元の過剰サイズまで自動的に正しくなるわけではありません。移行後の再評価を計画に入れます。

調査前に変数を設定する

以降のコマンドでは、リージョン、インスタンスID、調査期間を変数に入れて使います。IDや期間を何度も手入力しないため、対象間違いを減らせます。

ターミナル
# 対象環境に合わせて変更する。
export AWS_REGION="ap-northeast-1"
export INSTANCE_ID="i-0123456789abcdef0"

# Amazon Linux 2023など、GNU dateを使う環境で直近14日を指定する。
export START_TIME="$(date -u -d '14 days ago' '+%Y-%m-%dT%H:%M:%SZ')"
export END_TIME="$(date -u '+%Y-%m-%dT%H:%M:%SZ')"

# macOSで実行する場合は、START_TIMEだけこちらを使う。
# export START_TIME="$(date -u -v-14d '+%Y-%m-%dT%H:%M:%SZ')"

# 14日分を1,440データポイント以内で取得するため、15分単位にする。
export PERIOD=900

# AWS CLIとjqを利用できることを確認する。
aws --version
jq --version

# 誤ったAWSアカウントを調査しないよう、実行主体とアカウントIDを確認する。
aws sts get-caller-identity \
  --query '{Account:Account,Arn:Arn}' \
  --output table

jqがない場合、macOSではbrew install jq、Amazon Linux 2023ではsudo dnf install -y jqで導入できます。

get-metric-statisticsは、1回の呼び出しで最大1,440データポイントを返します。14日分を5分単位で要求すると上限を超えるため、ここでは15分単位に集約します。1分単位の短いピークを調べるときは、調査期間を短くします。期間と粒度の条件は、GetMetricStatisticsのAPIリファレンスで確認できます。

EC2の現行構成を最初に確認する

メトリクスを見る前に、現在のインスタンスタイプ、CPUアーキテクチャ、モニタリング設定を確認します。

ターミナル
# 対象EC2の現在値を一覧表示する。
aws ec2 describe-instances \
  --region "$AWS_REGION" \
  --instance-ids "$INSTANCE_ID" \
  --query 'Reservations[0].Instances[0].{Name:Tags[?Key==`Name`]|[0].Value,InstanceId:InstanceId,Type:InstanceType,State:State.Name,AZ:Placement.AvailabilityZone,Architecture:Architecture,CoreCount:CpuOptions.CoreCount,ThreadsPerCore:CpuOptions.ThreadsPerCore,Monitoring:Monitoring.State,EbsOptimized:EbsOptimized}' \
  --output table

# 後続の比較コマンドで使うため、現在のインスタンスタイプを変数へ入れる。
export INSTANCE_TYPE="$(aws ec2 describe-instances \
  --region "$AWS_REGION" \
  --instance-ids "$INSTANCE_ID" \
  --query 'Reservations[0].Instances[0].InstanceType' \
  --output text)"

# 現在のインスタンスタイプのvCPU、メモリ、ネットワーク性能を確認する。
aws ec2 describe-instance-types \
  --region "$AWS_REGION" \
  --instance-types "$INSTANCE_TYPE" \
  --query 'InstanceTypes[0].{Type:InstanceType,vCPU:VCpuInfo.DefaultVCpus,MemoryMiB:MemoryInfo.SizeInMiB,Network:NetworkInfo.NetworkPerformance}' \
  --output table

Monitoringdisabledなら基本モニタリング、enabledなら詳細モニタリングです。名称だけを見ると監視自体が無効に見えますが、disabledでも基本モニタリングのメトリクスは送信されます。

接続中のEBSも同じ段階で確認します。

ターミナル
# OSから見えるデバイス名とEBSボリュームIDの対応を確認する。
aws ec2 describe-instances \
  --region "$AWS_REGION" \
  --instance-ids "$INSTANCE_ID" \
  --query 'Reservations[0].Instances[0].BlockDeviceMappings[].{DeviceName:DeviceName,VolumeId:Ebs.VolumeId,DeleteOnTermination:Ebs.DeleteOnTermination}' \
  --output table

# 接続中EBSのタイプ、容量、IOPS、スループットを確認する。
aws ec2 describe-volumes \
  --region "$AWS_REGION" \
  --filters "Name=attachment.instance-id,Values=$INSTANCE_ID" \
  --query 'Volumes[].{VolumeId:VolumeId,Type:VolumeType,SizeGiB:Size,IOPS:Iops,ThroughputMiBps:Throughput,Encrypted:Encrypted,State:State}' \
  --output table

迷ったときの調査順

コマンドを闇雲に実行するのではなく、遅延やエラーが起きた時刻を起点に、次の順で調べます。

順番 確認すること 主な手段 次の判断
1 現在のEC2・EBS設定 describe-instancesdescribe-volumes 想定した構成か
2 遅かった時刻と処理 アプリケーションログ、ジョブ履歴 調査する時間帯を絞れるか
3 CPU・メモリ・EBS・ネットワーク CloudWatch どのリソースが同時に変化したか
4 プロセス・コア・デバイス mpstatpidstatiostat OS内の原因を特定できるか
5 EC2・EBSの性能上限 describe-instance-types、ExceededCheck 設定値や上限へ到達したか
6 変更候補 Compute Optimizer、負荷試験 変更後も性能要件を満たすか

CPUが高いという事実だけでサイズを上げません。応答時間や処理量が悪化した同じ時刻にCPUが高いのか、I/O待ちやメモリ不足が先に起きていないかを突き合わせます。

CloudWatchのコマンドでデータが返らないときは、次を順に確認します。

  1. AWS_REGIONが対象EC2と同じか
  2. インスタンスIDやボリュームIDを取り違えていないか
  3. START_TIMEEND_TIMEがUTCで、実データがある期間か
  4. 名前空間、メトリクス名、ディメンション名が一致しているか
  5. CloudWatch Agentのカスタムメトリクスなら、AgentとIAMロールが正常か

3. CPUを見る

CPUは平均値だけでなく、ピークの高さと継続時間を見ます。

パターン 考えられる状態 次に確認すること
常にCPUが高い CPUボトルネックの可能性 プロセス別使用率、スレッド数、スケールアップ/アウト
短時間だけ高い 一時的なピーク 応答時間の悪化、T系のCPUクレジット
CPUは低いのに遅い CPU以外がボトルネック メモリ、EBS、ロック、外部API、ネットワーク
1コアだけ高い シングルスレッド処理 vCPUを増やして速くなる実装か

CloudWatchのEC2標準メトリクスは、デフォルトで5分間隔で送信されます。詳細モニタリングを有効にすると1分間隔にできます。短いピークを評価するときは取得間隔も確認します。詳しい対象メトリクスと間隔は、AWS公式のEC2メトリクス一覧で確認できます。

ターミナル
# CPU使用率を時刻順に表示する。
# Averageは期間内の平均、Maximumは期間内の最大値。
aws cloudwatch get-metric-statistics \
  --region "$AWS_REGION" \
  --namespace AWS/EC2 \
  --metric-name CPUUtilization \
  --dimensions "Name=InstanceId,Value=$INSTANCE_ID" \
  --statistics Average Maximum \
  --period "$PERIOD" \
  --start-time "$START_TIME" \
  --end-time "$END_TIME" \
  --query 'sort_by(Datapoints,&Timestamp)[].{Time:Timestamp,Average:Average,Maximum:Maximum}' \
  --output table

期間全体を1つの数字で比較したい場合は、各15分平均の平均値、P95、最大値をjqで集計します。

ターミナル
# CPUUtilizationの15分平均をJSONで取得し、期間全体を要約する。
aws cloudwatch get-metric-statistics \
  --region "$AWS_REGION" \
  --namespace AWS/EC2 \
  --metric-name CPUUtilization \
  --dimensions "Name=InstanceId,Value=$INSTANCE_ID" \
  --statistics Average \
  --period "$PERIOD" \
  --start-time "$START_TIME" \
  --end-time "$END_TIME" \
  --query 'Datapoints[].Average' \
  --output json | \
jq 'sort as $values
    | ($values | length) as $count
    | if $count == 0 then
        {samples: 0}
      else
        {
          samples: $count,
          average: ($values | add / $count),
          p95: $values[((($count * 0.95) | ceil) - 1)],
          max: $values[-1]
        }
      end'

ここで求めているP95は、CPU使用率の15分平均値を並べたP95です。Web APIの応答時間に対するP95とは別物です。Averageは全体傾向、P95は高負荷帯、Maximumは最も高かった期間を知るために使います。

CloudWatchでCPUが高かった時刻を特定したら、OS内でコア別・プロセス別に確認します。

mpstatpidstatvmstatの役割

3つともLinuxの稼働状況を調べるコマンドですが、見る範囲が異なります。

コマンド 主に見る範囲 分かること
mpstat CPU全体・CPUコア別 各コアの使用率、I/O待ち、アイドル率。特定の1コアに処理が偏っていないか確認できる
pidstat プロセス別 どのPIDがCPU、メモリ、ディスクI/Oを使っているか確認できる
vmstat サーバー全体 実行待ち、メモリ、スワップ、ブロックI/O、CPUを一度に確認できる

mpstatpidstatsysstatパッケージに含まれます。vmstatは通常、procps-ngパッケージに含まれます。

ターミナル
# CPU調査用のsysstatをインストールする。
sudo dnf install -y sysstat

# 全CPUとコア別の使用率を1秒間隔で5回表示する。
mpstat -P ALL 1 5

# プロセスごとのCPU・メモリ・ディスクI/Oを1秒間隔で5回表示する。
pidstat -u -r -d 1 5

mpstat -P ALL 1 5-P ALLは全CPUとコア別の統計、1は1秒間隔、5は5回出力する指定です。主に次の列を見ます。

  • %usr: アプリケーションなど、ユーザー空間で使ったCPU時間
  • %sys: OSカーネルで使ったCPU時間
  • %iowait: 未完了のディスクI/Oがある状態で、CPUが待っていた時間
  • %idle: CPUが使われていなかった時間

特定コアだけ%idleが継続的に低い場合は、シングルスレッド処理などの偏りを疑います。%iowaitが高い場合は、CPU不足と決めつけず、EBSやファイルシステムも確認します。

pidstat -u -r -d 1 5-uはCPU使用率、-rはページフォールトとメモリ、-dはディスクI/Oの統計を表示します。CPU使用率が高いPIDや、読み書き量が大きいPIDを探すことで、原因となっているプロセスを絞り込めます。

T系ではCPUクレジットも見る

T3やT4gなどは、平常時は低負荷で、必要なときだけCPUをバーストする用途に向いています。

  • CPUCreditBalance: 利用できるCPUクレジットの残量
  • CPUCreditUsage: 使用したCPUクレジット
  • CPUSurplusCreditBalance: Unlimitedモードでベースラインを超えて使用した分

T3やT4gは、通常の起動ではデフォルトでUnlimitedモードになります。ベースラインを超えるCPU使用が長時間続くと追加料金の対象になる可能性があるため、常時CPUを使う処理ではM系やC系とも比較します。Dedicated Hostなど、起動方法によって初期設定が異なる場合は個別に確認してください。

ターミナル
# T系インスタンスのクレジット設定がstandardかunlimitedか確認する。
aws ec2 describe-instance-credit-specifications \
  --region "$AWS_REGION" \
  --instance-ids "$INSTANCE_ID" \
  --query 'InstanceCreditSpecifications[].{InstanceId:InstanceId,CpuCredits:CpuCredits}' \
  --output table

# 調査期間内のCPUクレジット残高の最小値を確認する。
aws cloudwatch get-metric-statistics \
  --region "$AWS_REGION" \
  --namespace AWS/EC2 \
  --metric-name CPUCreditBalance \
  --dimensions "Name=InstanceId,Value=$INSTANCE_ID" \
  --statistics Minimum \
  --period "$PERIOD" \
  --start-time "$START_TIME" \
  --end-time "$END_TIME" \
  --query 'sort_by(Datapoints,&Timestamp)[].{Time:Timestamp,Minimum:Minimum}' \
  --output table

T系以外では、CPUクレジットのデータは返りません。T系でCPUCreditBalanceが繰り返し低下する場合は、CPU使用の継続時間とCPUSurplusCreditBalanceも確認します。

4. メモリを見る

EC2がデフォルトでCloudWatchへ送るメトリクスには、OS内部のメモリ使用率は含まれません。CloudWatch Agentなどを使って取得します。

ターミナル
# 利用可能メモリとスワップを確認する。
free -h

# 1秒間隔でCPU、メモリ、スワップ、I/O待ちを5回確認する。
vmstat 1 5

# RSSが大きいプロセスを上位10件表示する。RSSの単位はKiB。
ps -eo pid,comm,%mem,rss --sort=-rss | head -n 11

# 直近14日間にOOM Killerが動いた形跡を探す。
sudo journalctl -k --since '14 days ago' \
  | grep -Ei 'out of memory|oom-killer|killed process'

Linuxでは空きメモリをページキャッシュに使うため、usedだけを見て不足と判定しません。available、スワップ、OOM Killer、アプリケーションのヒープ使用量を一緒に確認します。

vmstat 1 5は、1秒間隔で5回出力します。1行目には起動後からの平均が含まれるため、現在の瞬間的な傾向は2行目以降を中心に見ます。

意味 確認のポイント
r 実行中またはCPUの実行待ちにいるプロセス数 vCPU数を継続的に上回る場合は、CPU待ちが発生している可能性がある
si / so スワップからの読み込み量・スワップへの書き出し量 継続的に値が出る場合は、メモリ圧迫の可能性がある
bi / bo ブロックデバイスからの読み込み量・書き出し量 I/O量の増加時刻とwa、EBSメトリクスを照合する
wa CPUがI/O完了を待っていた時間の割合 継続的に高い場合は、EBSやファイルシステム側も調べる

CloudWatch Agentで取得する例

Amazon Linux 2023での最小例です。エージェントがCloudWatchへメトリクスを送れるIAMロールも必要です。以下のJSONは/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.jsonとして保存します。

ターミナル
# CloudWatch Agentをインストールする。
sudo dnf install -y amazon-cloudwatch-agent
amazon-cloudwatch-agent.json
{
  "agent": {
    "metrics_collection_interval": 60
  },
  "metrics": {
    "namespace": "CWAgent",
    "append_dimensions": {
      "InstanceId": "${aws:InstanceId}"
    },
    "metrics_collected": {
      "mem": {
        "measurement": ["used_percent"]
      },
      "swap": {
        "measurement": ["used_percent"]
      },
      "disk": {
        "measurement": ["used_percent"],
        "resources": ["*"]
      }
    }
  }
}

JSONにはコメントを書けないため、意図を補足します。memswapused_percentは、CloudWatch上でそれぞれmem_used_percentswap_used_percentとして送信されます。diskはファイルシステム使用率を取得します。

ターミナル
# 作成したJSONを読み込み、EC2モードでAgentを起動する。
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
  -a fetch-config \
  -m ec2 \
  -s \
  -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json

CloudWatch Agentから送信するメトリクスはカスタムメトリクスとして課金対象になります。必要な項目と取得間隔を選びます。

Agentを起動したら、CloudWatchへメモリ使用率が届いているか確認します。

ターミナル
# mem_used_percentが対象インスタンスのディメンションで存在するか確認する。
aws cloudwatch list-metrics \
  --region "$AWS_REGION" \
  --namespace CWAgent \
  --metric-name mem_used_percent \
  --dimensions "Name=InstanceId,Value=$INSTANCE_ID"

# メモリ使用率の平均値と最大値を時刻順に表示する。
aws cloudwatch get-metric-statistics \
  --region "$AWS_REGION" \
  --namespace CWAgent \
  --metric-name mem_used_percent \
  --dimensions "Name=InstanceId,Value=$INSTANCE_ID" \
  --statistics Average Maximum \
  --period "$PERIOD" \
  --start-time "$START_TIME" \
  --end-time "$END_TIME" \
  --query 'sort_by(Datapoints,&Timestamp)[].{Time:Timestamp,Average:Average,Maximum:Maximum}' \
  --output table

list-metricsで見つからない場合は、Agentの起動状態、設定ファイル、EC2のIAMロール、リージョンを順に確認します。メモリ使用率だけでなく、freeavailable、スワップ増加、OOM、アプリケーションのヒープ上限を合わせて判断します。

5. ネットワークを見る

CPUとメモリに余裕があっても、ネットワークが上限に近づくと遅延やパケットドロップにつながります。

  • NetworkIn / NetworkOut: 受信・送信バイト数
  • NetworkPacketsIn / NetworkPacketsOut: 受信・送信パケット数
  • conntrack_allowance_exceeded: 追跡可能な接続数の上限超過
  • bw_in_allowance_exceeded / bw_out_allowance_exceeded: 入出力帯域の上限超過
  • pps_allowance_exceeded: 1秒あたりパケット数の上限超過

allowance系はENAドライバのethtool統計などから確認します。送受信量だけでなく、パケット数や接続数の上限もボトルネックになります。

ターミナル
# NetworkOutを平均Mbpsへ変換して時刻順に表示する。
# CloudWatchのNetworkOutは、期間内に送信した合計バイト数。
aws cloudwatch get-metric-statistics \
  --region "$AWS_REGION" \
  --namespace AWS/EC2 \
  --metric-name NetworkOut \
  --dimensions "Name=InstanceId,Value=$INSTANCE_ID" \
  --statistics Sum \
  --period "$PERIOD" \
  --start-time "$START_TIME" \
  --end-time "$END_TIME" \
  --output json | \
jq --argjson period "$PERIOD" '
  .Datapoints
  | sort_by(.Timestamp)
  | map({time: .Timestamp, average_mbps: (.Sum * 8 / $period / 1000000)})'

CloudWatchの送受信量に余裕があっても、PPSや接続追跡の上限超過が起きることがあります。ENAドライバの統計をEC2内で確認します。

ターミナル
# デフォルトルートで使うネットワークインターフェイス名を取得する。
INTERFACE="$(ip route show default | awk '{print $5; exit}')"

# 0より大きいallowance超過カウンターがないか確認する。
sudo ethtool -S "$INTERFACE" \
  | grep -E 'bw_(in|out)_allowance_exceeded|pps_allowance_exceeded|conntrack_allowance_exceeded'

これらは累積カウンターです。1回の値だけでなく、時間を空けて再取得して増えているかを確認します。

6. インスタンスファミリーを選ぶ

次の表は、AWSの分類をもとに最初の候補を選ぶために簡略化したものです。

特徴 候補 用途例 注意
CPUとメモリのバランス型 M系 Webサーバー、業務アプリ 迷ったときの比較基準にしやすい
CPU比率が大きい C系 計算処理、エンコード、高トラフィックWeb メモリ容量を先に確認する
メモリ比率が大きい R系 インメモリDB、大きなキャッシュ メモリ不足の根拠を確認する
低負荷で一時的にCPUが必要 T系 小規模Web、検証環境 CPUクレジットとUnlimited料金を見る
ローカルNVMeのI/Oを重視 I系など 分散DB、一時キャッシュ Instance Storeの永続性を別途考える

ファミリー名だけで決めず、世代、x86/Arm、ローカルストレージの有無、ネットワークとEBS帯域を比較します。

ターミナル
# 東京リージョンでM/C/Rファミリーのlargeサイズを比較する。
# MemoryMiBはMiB表記のため、GiBで見る場合は1,024で割る。
aws ec2 describe-instance-types \
  --region ap-northeast-1 \
  --instance-types m7i.large c7i.large r7i.large \
  --query 'InstanceTypes[].{Type:InstanceType,vCPU:VCpuInfo.DefaultVCpus,MemoryMiB:MemoryInfo.SizeInMiB,Network:NetworkInfo.NetworkPerformance,EBSBaselineMbps:EbsInfo.EbsOptimizedInfo.BaselineBandwidthInMbps,EBSMaxMbps:EbsInfo.EbsOptimizedInfo.MaximumBandwidthInMbps,EBSBaselineIOPS:EbsInfo.EbsOptimizedInfo.BaselineIops,EBSMaxIOPS:EbsInfo.EbsOptimizedInfo.MaximumIops}' \
  --output table

NetworkPerformanceUp toは、常にその速度を維持できるという意味ではありません。小さいサイズでは、ベースラインとバーストの扱いも確認します。

7. EBSは容量・IOPS・スループット・レイテンシで決める

EBSを「500GB」のように容量だけで決めると、空き容量があるのに遅いという状態が起きます。

観点 質問 主な確認値
容量 何GiB保存するか 現在使用量、増加率、保持期間
IOPS 1秒に何回の読み書きが必要か ReadOps、WriteOps、I/Oサイズ
スループット 1秒に何MiB転送するか ReadBytes、WriteBytes
レイテンシ 1回のI/Oが何msで完了するか ReadLatency、WriteLatency、QueueLength

EBSボリュームタイプ

タイプ 特徴 最初に検討する用途
gp3 容量とIOPS・スループットを独立して設定できる汎用SSD Web、業務アプリ、開発環境などの一般用途
gp2 容量と基準IOPSが連動する旧世代の汎用SSD 既存環境の移行元として見かける
io2 高IOPS、低レイテンシ、高い耐久性を重視するSSD ミッションクリティカルなDB、gp3の上限を超える用途
st1 大きなデータの順次読み書きを重視するHDD ログ処理、ビッグデータなど
sc1 低頻度アクセス向けの低コストHDD 頻繁に読み書きしないデータ

多くの一般用途では、まずgp3を候補にします。gp3はストレージ料金に3,000 IOPSと125 MiB/sの基準性能が含まれます。

必要に応じてIOPSは最大80,000、スループットは最大2,000 MiB/sまで追加設定できます。上限にはボリュームサイズとIOPSの比率条件があり、追加分は課金対象です。

gp3gp2のようなI/Oクレジットによるバースト方式ではなく、設定したIOPSとスループットを持続的に提供する設計です。

IOPSとスループットの関係

基本式
スループット = IOPS × 1回あたりのI/Oサイズ

1回16 KiBのI/Oを1秒間に6,000回行う場合は次のとおりです。

計算例
6,000 IOPS × 16 KiB = 96,000 KiB/s = 93.75 MiB/s

一方、256 KiBの大きなI/Oを1,000回行うと250 MiB/sになります。小さなランダムI/OではIOPS、大きな順次I/Oではスループットが先に上限へ達することがあります。

8. EBSのボトルネックを4層に分ける

EBSが遅いときは、ボリュームの設定だけを増やさず、次の4層に分けます。

1. OSとアプリケーション

ファイルシステムが満杯、メモリスワップが多い、アプリケーションが同期書き込みを多用するなどの要因を確認します。

ターミナル
# ブロックデバイスとマウント先を確認する。
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS

# ファイルシステムの使用量と空き容量を確認する。
df -hT

# sysstatをインストールし、デバイス別のI/Oを1秒間隔で確認する。
sudo dnf install -y sysstat
iostat -xz 1

iostatではawaitaqu-sz%utilなどを見ます。単一のしきい値だけで判定せず、応答時間とアプリケーションログと一緒に見ます。

2. EBSボリュームの上限

EBSのメトリクスはAWS/EBS名前空間へ1分間隔で自動送信されます。対応するNitroベースEC2では、IOPS、スループット、レイテンシを直接読めるメトリクスが追加されています。対象条件と統計値は、AWS公式のEBSメトリクス一覧で確認できます。

確認したいこと Nitroで使える直接メトリクス 従来メトリクスからの計算
読み書き合計IOPS VolumeAvgIOPS VolumeReadOpsVolumeWriteOpsSum / Periodを合計
読み書き合計スループット VolumeAvgThroughput VolumeReadBytesVolumeWriteBytesSum / Period / 1,048,576を合計
読みレイテンシ VolumeAvgReadLatency VolumeTotalReadTime / VolumeReadOps × 1,000
書きレイテンシ VolumeAvgWriteLatency VolumeTotalWriteTime / VolumeWriteOps × 1,000
平均キュー長 - VolumeQueueLengthAverage

VolumeAvgIOPSの単位はOps/s、VolumeAvgThroughputはKiB/s、レイテンシはミリ秒です。Multi-AttachではInstanceIdディメンションも使うなど条件が変わるため、通常の単一アタッチと同じクエリをそのまま使わないようにします。

対応するNitroベースEC2では、上限超過を直接確認できる次のメトリクスも利用できます。

  • VolumeIOPSExceededCheck: プロビジョンしたIOPSを継続的に超えようとしたか
  • VolumeThroughputExceededCheck: プロビジョンしたスループットを継続的に超えようとしたか

1が上限超過を示します。Magneticボリューム、Multi-Attach有効ボリュームなど、対象外の条件がある点に注意します。

ターミナル
# 調査するEBSボリュームIDを設定する。
export VOLUME_ID="vol-0123456789abcdef0"

# IOPS・スループット・レイテンシの最大値を時刻順に表示する。
# Nitro非対応などでメトリクスがない場合は、何も返らない。
for METRIC in \
  VolumeAvgIOPS \
  VolumeAvgThroughput \
  VolumeAvgReadLatency \
  VolumeAvgWriteLatency
do
  echo "=== $METRIC ==="
  aws cloudwatch get-metric-statistics \
    --region "$AWS_REGION" \
    --namespace AWS/EBS \
    --metric-name "$METRIC" \
    --dimensions "Name=VolumeId,Value=$VOLUME_ID" \
    --statistics Maximum \
    --period "$PERIOD" \
    --start-time "$START_TIME" \
    --end-time "$END_TIME" \
    --query 'sort_by(Datapoints,&Timestamp)[].{Time:Timestamp,Maximum:Maximum}' \
    --output table
done

上限超過チェックは、Maximum1になった時刻がないかを見ます。

ターミナル
# IOPSまたはスループットの上限超過が発生した時刻を確認する。
for METRIC in VolumeIOPSExceededCheck VolumeThroughputExceededCheck
do
  echo "=== $METRIC ==="
  aws cloudwatch get-metric-statistics \
    --region "$AWS_REGION" \
    --namespace AWS/EBS \
    --metric-name "$METRIC" \
    --dimensions "Name=VolumeId,Value=$VOLUME_ID" \
    --statistics Maximum \
    --period "$PERIOD" \
    --start-time "$START_TIME" \
    --end-time "$END_TIME" \
    --query 'sort_by(Datapoints[?Maximum==`1`],&Timestamp)[].{Time:Timestamp,Exceeded:Maximum}' \
    --output table
done

直接メトリクスを利用できない環境では、従来メトリクスを期間の秒数で割ります。次は読み取りIOPSの例です。

ターミナル
# VolumeReadOpsの期間内合計を秒数で割り、平均Read IOPSへ変換する。
aws cloudwatch get-metric-statistics \
  --region "$AWS_REGION" \
  --namespace AWS/EBS \
  --metric-name VolumeReadOps \
  --dimensions "Name=VolumeId,Value=$VOLUME_ID" \
  --statistics Sum \
  --period "$PERIOD" \
  --start-time "$START_TIME" \
  --end-time "$END_TIME" \
  --output json | \
jq --argjson period "$PERIOD" '
  .Datapoints
  | sort_by(.Timestamp)
  | map({time: .Timestamp, average_read_iops: (.Sum / $period)})'

書き込みIOPSはVolumeWriteOps、読み取りスループットはVolumeReadBytes、書き込みスループットはVolumeWriteBytesへ置き換えます。Bytes系はさらに1,048,576で割るとMiB/sになります。

現在のEBS設定をもう一度確認するときは、対象ボリュームIDで絞ります。

ターミナル
# 対象EBSの現在設定と接続先を確認する。
aws ec2 describe-volumes \
  --region "$AWS_REGION" \
  --volume-ids "$VOLUME_ID" \
  --query 'Volumes[].{VolumeId:VolumeId,Type:VolumeType,SizeGiB:Size,IOPS:Iops,ThroughputMiBps:Throughput,InstanceId:Attachments[0].InstanceId,Device:Attachments[0].Device}' \
  --output table

3. EC2インスタンス側のEBS帯域

EBSボリュームに8,000 IOPSを設定しても、EC2側が持続できるIOPSやスループットを超えていれば性能を使い切れません。

性能の上限
実効EBS性能 = min(接続ボリュームの合計性能, EC2インスタンスのEBS性能上限)

小さいインスタンスでは、EBS帯域にベースラインと最大値がある場合があります。長時間バッチは、最大値だけでなくベースラインでも成立するか確認します。

ターミナル
# 現在のインスタンスタイプが持つEBS性能の基準値と最大値を確認する。
aws ec2 describe-instance-types \
  --region "$AWS_REGION" \
  --instance-types "$INSTANCE_TYPE" \
  --query 'InstanceTypes[0].{Type:InstanceType,BaselineIOPS:EbsInfo.EbsOptimizedInfo.BaselineIops,MaximumIOPS:EbsInfo.EbsOptimizedInfo.MaximumIops,BaselineMBps:EbsInfo.EbsOptimizedInfo.BaselineThroughputInMBps,MaximumMBps:EbsInfo.EbsOptimizedInfo.MaximumThroughputInMBps}' \
  --output table

ベースラインが0nullになる場合は、そのインスタンスタイプの仕様表も確認します。接続する全EBSの合計負荷と比較し、1ボリュームだけで判断しません。

4. スナップショットから復元したEBS

スナップショットから作成したEBSは、初回アクセス時にブロックを取得するため、初期化が完了するまで性能が安定しないことがあります。

性能試験前に、Fast Snapshot Restore、ボリューム初期化レートの指定、手動初期化のいずれかを検討します。追加料金やI/O負荷があるため、本番要件と日程に合わせて選びます。

9. 具体的なサイジング例

ここからは、筆者の実務経験をもとにした説明用の例です。AWS公式の推奨しきい値ではありません。

項目 実測値 初期選定の考え方
CPU P95 55%、最大85% ピーク時の応答時間を負荷試験で確認
メモリ P95 11 GiB OS分も含め16 GiB程度を起点にする
EBS使用量 320 GiB 1年の増加分と作業領域を含め500 GiBとする
EBS IOPS P95 4,500、最大5,400 6,000 IOPSを候補にする
EBSスループット P95 100 MiB/s、最大180 MiB/s 250 MiB/sを候補にする
ネットワーク 最大150 Mbps インスタンス上限と十分に離れているか確認

初期候補は、M系の4 vCPU・16 GiBメモリ程度と、gp3 500 GiB・6,000 IOPS・250 MiB/sです。

この時点で決定ではありません。対象EC2のEBSベースラインで6,000 IOPSと250 MiB/sの必要時間を支えられるか確認します。不足する場合はEC2サイズ、ファミリー、I/O設計を見直します。

10. EBSの設定を変更する

Elastic Volumesに対応する構成では、EBSをデタッチせず、EC2を再起動せずに容量、ボリュームタイプ、IOPS、スループットを変更できます。

ターミナル
# 変更前にスナップショット、現在値、対象IDを確認する。
# gp3 500 GiB、6,000 IOPS、250 MiB/sへ変更する例。
aws ec2 modify-volume \
  --region ap-northeast-1 \
  --volume-id vol-0123456789abcdef0 \
  --volume-type gp3 \
  --size 500 \
  --iops 6000 \
  --throughput 250

# 変更の進行状態を確認する。
aws ec2 describe-volumes-modifications \
  --region ap-northeast-1 \
  --volume-ids vol-0123456789abcdef0

EBSの容量は増やせますが、同じボリュームを後から縮小できません。縮小する場合は、小さい新規ボリュームへデータを移行します。

容量を増やした後は、OS側のパーティションやファイルシステムの拡張が別途必要です。実行コマンドはXFS、ext4、Windowsで異なるため、対象を確認してから作業します。

ボリュームの変更はキャンセルできません。同じボリュームは、前の変更が完了している条件で、ローリング24時間内に最大4回まで変更できます。

11. Compute Optimizerを判断材料にする

AWS Compute OptimizerはCloudWatchメトリクスを分析し、EC2やEBSの最適化候補を示します。利用前にアカウントまたはOrganizations管理アカウントからオプトインします。

EC2とAuto Scalingグループの推奨には、過去14日間に少なくとも30時間のCloudWatchメトリクスが必要です。有料の拡張インフラストラクチャメトリクスを有効にすると、ルックバック期間を最大93日へ延長できます。

EBSの推奨は、ボリュームが実行中のEC2へ少なくとも30時間連続で接続されている必要があります。

  • メモリを分析させるには、CloudWatch Agentのmem_used_percentなどが必要
  • 推奨の節約額を表示するにはCost Explorerの有効化が必要
  • キャンペーン、新機能、未実行の月次処理は別途考慮する
  • 変更前にテストし、変更後の応答時間とエラー率を確認する
ターミナル
# Compute Optimizerへオプトイン済みか確認する。
aws compute-optimizer get-enrollment-status \
  --region "$AWS_REGION" \
  --query '{Status:status,StatusReason:statusReason,MemberAccountsEnrolled:memberAccountsEnrolled}' \
  --output table

# EC2とEBSのARNを組み立てる。
export ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
export INSTANCE_ARN="arn:aws:ec2:${AWS_REGION}:${ACCOUNT_ID}:instance/${INSTANCE_ID}"
export VOLUME_ARN="arn:aws:ec2:${AWS_REGION}:${ACCOUNT_ID}:volume/${VOLUME_ID}"

# 現在のEC2に対する判定、理由、分析期間を確認する。
aws compute-optimizer get-ec2-instance-recommendations \
  --region "$AWS_REGION" \
  --instance-arns "$INSTANCE_ARN" \
  --query 'instanceRecommendations[0].{CurrentType:currentInstanceType,Finding:finding,Reasons:findingReasonCodes,LookbackDays:lookBackPeriodInDays}' \
  --output json

# 推奨候補を順位、性能リスク、移行難易度、推定削減額と一緒に表示する。
aws compute-optimizer get-ec2-instance-recommendations \
  --region "$AWS_REGION" \
  --instance-arns "$INSTANCE_ARN" \
  --query 'instanceRecommendations[0].recommendationOptions[].{Rank:rank,Type:instanceType,PerformanceRisk:performanceRisk,MigrationEffort:migrationEffort,EstimatedMonthlySavings:savingsOpportunity.estimatedMonthlySavings.value}' \
  --output table

# 対象EBSの推奨タイプ、容量、IOPS、スループットを表示する。
aws compute-optimizer get-ebs-volume-recommendations \
  --region "$AWS_REGION" \
  --volume-arns "$VOLUME_ARN" \
  --query 'volumeRecommendations[0].volumeRecommendationOptions[].{Rank:rank,Type:configuration.volumeType,SizeGiB:configuration.volumeSize,IOPS:configuration.volumeBaselineIOPS,ThroughputMBps:configuration.volumeBaselineThroughput,PerformanceRisk:performanceRisk,EstimatedMonthlySavings:savingsOpportunity.estimatedMonthlySavings.value}' \
  --output table

FindingUnavailable、または推奨候補が空の場合は、オプトイン状態、分析に必要な時間、対象リソースの条件を確認します。EC2とAuto Scalingグループには過去14日間で少なくとも30時間、EBSには実行中EC2へ30時間連続で接続された実績が必要です。要件はCompute Optimizerの公式リソース要件で更新を確認してください。

PerformanceRiskは0から4の範囲で、値が高いほど推奨構成が性能要件を満たせない可能性が高いことを示します。削減額だけで並べず、FindingReasonCodes、移行難易度、将来のピークも合わせて確認します。

Compute Optimizerは正解を自動適用するサービスではなく、比較候補を出すサービスとして使います。

12. EC2サイズ変更の注意

EBS-backedインスタンスのインスタンスタイプを変更する場合、基本的にEC2の停止と起動が必要です。変更先との互換性も確認します。

  • AMIのCPUアーキテクチャが一致するか
  • ENAなどのネットワークドライバが対応しているか
  • NitroベースのNVMeデバイス名の違いに対応できるか
  • 接続済みEBSボリューム数が変更先の上限以内か
  • ライセンス、CPUオプション、Dedicated Hostの制約がないか
  • 停止・起動で自動割り当てのパブリックIPv4アドレスが変わる影響がないか
  • 起動後にOS、エージェント、アプリケーションを確認できるか

Arm系のGravitonインスタンスへ変える場合は、x86_64のAMIのままインスタンスタイプだけ変更できません。Arm対応AMI、アプリケーション、ライブラリ、コンテナイメージで別EC2を構築し、移行試験します。

13. 負荷試験で確認する

サイジングの最終判断は、カタログ仕様ではなく、本番に近い条件の負荷試験で行います。

  • 処理量と同時接続数
  • P50、P95、P99の応答時間
  • エラー率とタイムアウト数
  • CPUとメモリ
  • EBSのIOPS、スループット、レイテンシ、キュー
  • ネットワークの送受信量と上限超過
  • 外部API、DB、キャッシュの待ち時間

通常負荷、予想ピーク、1台障害やバッチ重複を含む高負荷の3パターンを分けます。負荷生成側が先に上限へ達しないようにし、本番データや外部サービスへ影響しない検証環境で行います。

14. サイジングシートの例

レビューでは、次のように実測と選定理由を残します。

項目 現状・予測 ピーク 初期選定 再確認日
vCPU 4 vCPUでP95 55% 85% 4 vCPUから負荷試験 本番開始2週間後
メモリ P95 11 GiB 12 GiB 16 GiB 本番開始2週間後
EBS容量 320 GiB 340 GiB 500 GiB 毎月
EBS IOPS P95 4,500 5,400 6,000 IOPS 本番開始2週間後
EBSスループット P95 100 MiB/s 180 MiB/s 250 MiB/s 本番開始2週間後
ネットワーク P95 100 Mbps 150 Mbps 仕様と負荷試験で決定 本番開始2週間後

余裕は一律30%のように決めません。Auto Scalingで台数を増やせるか、月次処理が未計測か、1台障害時に全負荷を受けるか、変更調整にどれくらい時間がかかるかで変えます。

よくある失敗

オンプレのスペックをそのまま写す

オンプレの調達時点の余裕までAWSに移すと、使っていないサイズに毎月支払い続けることがあります。実測値と業務要件から選び直します。

CPU平均だけを見る

平均CPUが20%でも、業務ピークに100%が続いているかもしれません。Maximum、P95、ピークの継続時間を見ます。

メモリを測定しない

CPUしか見ずにサイズを下げると、スワップやOOMが発生する可能性があります。CloudWatch Agentまたは既存の監視ツールでメモリを測ります。

EBSの容量だけを増やす

gp3は容量とIOPS・スループットを分けて設定できます。遅さの原因がIOPSなのか、スループットなのか、EC2側の上限なのかを切り分けます。

カタログの最大値だけを見る

Up toやMaximumは、長時間維持できるベースラインと異なる場合があります。長時間バッチはベースライン値でも成立するか確認します。

Compute Optimizerの推奨をそのまま適用する

過去のメトリクスに含まれない未来のピーク、新機能、障害時の片系運転を別途考慮します。

実務チェックリスト

要件

  • 応答時間、処理量、バッチ終了時間を数値化した
  • 通常時とピーク時を分けた
  • データとトラフィックの成長率を確認した
  • 1台障害時の必要性能を確認した

EC2

  • CPUのAverage、Maximum、P95、継続時間を確認した
  • メモリ、スワップ、OOMの有無を確認した
  • T系ではCPUクレジットを確認した
  • ファミリー、世代、CPUアーキテクチャを比較した
  • ネットワークの帯域、PPS、接続数を確認した
  • 変更に必要な停止時間と互換性を確認した

EBS

  • 容量、増加率、保持期間を確認した
  • 読み書きIOPSを分けて確認した
  • 読み書きスループットを分けて確認した
  • I/Oサイズ、レイテンシ、QueueLengthを確認した
  • EBSボリュームとEC2側の上限を両方確認した
  • スナップショット復元後の初期化を考慮した
  • 容量変更後のファイルシステム拡張手順を確認した

検証と運用

  • 通常、ピーク、障害時の負荷試験を行った
  • 変更前後の応答時間、エラー率、コストを比較した
  • Compute Optimizerの推奨とパフォーマンスリスクを確認した
  • 本番開始後の再評価日を決めた
  • CloudWatchアラームと変更前へ戻す手順を用意した

参考・確認先

仕様確認日: 2026年8月27日

関連記事

まとめ

  • EC2サイジングは、要件を数値化してからCPU、メモリ、ネットワーク、EBSを測定する
  • EBSは容量、IOPS、スループット、レイテンシに分けて考える
  • EBSボリュームの設定だけでなく、EC2側のEBS帯域上限も確認する
  • Compute Optimizerは判断材料として使い、負荷試験後に適用する
  • 最初のサイズを正解にせず、本番開始後の再評価日まで決める

おわりに

EC2のサイジングは、「大きくして安心」ではなく、実測と性能要件をもとに選定理由を説明できることが大切です。EBSも容量だけではなく、IOPS、スループット、EC2側の帯域まで一緒に見ると、性能とコストの両方を改善できます。

Wealthy Designでは、AWS・Google Cloud・Azureの設計で、構築方法だけでなく性能、コスト、運用まで説明できるエンジニアリングを大切にしています。技術発信やエンジニア育成の取り組みは、会社サイトにまとめています。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?