EBS gp2 vs gp3: Why gp3 Wins on Cost and IOPS Flexibility

Picking the wrong EBS volume type is a silent cost leak — teams routinely over-provision gp2 storage just to hit an IOPS target, paying for terabytes they don't need. Understanding the architectural difference between gp2 and gp3 eliminates that waste entirely.

TL;DR

Attribute gp2 gp3
IOPS Scaling Model Coupled to storage size (3 IOPS/GB) Independent of storage size
Baseline IOPS 3 IOPS/GB (min 100, max 16,000) 3,000 IOPS included at any size
Max IOPS 16,000 (requires 5,334 GB) 16,000 (provisionable on any size)
Max Throughput 250 MB/s 1,000 MB/s
Burst Mechanism Credit-based burst to 3,000 IOPS No burst needed — 3,000 baseline always
Price (us-east-1) $0.10/GB-month $0.08/GB-month + $0.005/provisioned IOPS above 3k
Core Takeaway Use gp3 by default. It is cheaper at baseline and lets you scale IOPS without buying more storage.

Deep-Dive: The Architectural Difference

gp2 — The Coupled Model

gp2 ties performance directly to capacity. Think of it like a highway where the number of lanes is fixed by how long the road is — you cannot add lanes without extending the road.

  • IOPS formula: 3 IOPS per GB provisioned, hard-capped at 16,000 IOPS.
  • Burst bucket: Volumes under ~1 TB accumulate I/O credits (up to 5.4 million) and can burst to 3,000 IOPS temporarily.
  • The trap: To sustain 16,000 IOPS, you must provision at least 5,334 GB (~5.3 TB) — even if your data is only 200 GB. You pay for 5+ TB of storage to buy IOPS.

gp3 — The Decoupled Model

gp3 separates the storage capacity dial from the performance dial entirely. You provision GB and IOPS as two independent dimensions.

  • Baseline included: Every gp3 volume gets 3,000 IOPS and 125 MB/s throughput regardless of size — even a 1 GB volume.
  • Provisioned scaling: IOPS can be increased up to 16,000 and throughput up to 1,000 MB/s independently, billed separately.
  • No credit system: Performance is consistent and sustained — no burst exhaustion risk.

Data Flow: How IOPS Are Allocated

flowchart TD subgraph gp2_Model ["gp2 — Coupled IOPS"] A["Provision Storage Size\n(e.g., 200 GB)"] --> B["IOPS = 3 x GB\n= 600 IOPS"] B --> C{"Need 10,000 IOPS?"} C -->|"Yes"| D["Must provision\n~3,334 GB"] C -->|"No"| E["Use burst credits\n(temporary, depletable)"] end subgraph gp3_Model ["gp3 — Decoupled IOPS"] F["Provision Storage Size\n(e.g., 200 GB)"] --> G["Baseline: 3,000 IOPS\nincluded always"] G --> H{"Need 10,000 IOPS?"} H -->|"Yes"| I["Provision +7,000 IOPS\nindependently ($0.005/IOPS)"] H -->|"No"| J["Use 3,000 IOPS baseline\nNo extra cost"] end style gp2_Model fill:#fff3cd,stroke:#ffc107 style gp3_Model fill:#d4edda,stroke:#28a745

Cost Comparison: A Real Scenario

Scenario: You need 200 GB storage and 10,000 sustained IOPS in us-east-1.

gp2 Cost

  • To sustain 10,000 IOPS: must provision 10,000 ÷ 3 = 3,334 GB
  • Cost: 3,334 GB × $0.10 = $333.40/month

gp3 Cost

  • Storage: 200 GB × $0.08 = $16.00
  • Extra IOPS: (10,000 − 3,000) × $0.005 = $35.00
  • Total: $51.00/month

Result: gp3 saves ~$282/month (85% cheaper) for this workload. The savings compound at scale.

Migrating from gp2 to gp3 (CLI)

AWS supports live volume modification — no downtime, no detach required. Minimum IAM permissions needed: ec2:ModifyVolume and ec2:DescribeVolumesModifications.

Step 1: Identify gp2 volumes in your account

aws ec2 describe-volumes \
  --filters Name=volume-type,Values=gp2 \
  --query 'Volumes[*].{ID:VolumeId,Size:Size,IOPS:Iops,AZ:AvailabilityZone}' \
  --output table

Step 2: Modify a single volume to gp3

aws ec2 modify-volume \
  --volume-id vol-0abc1234def567890 \
  --volume-type gp3 \
  --iops 3000 \
  --throughput 125

Step 3: Monitor modification progress

aws ec2 describe-volumes-modifications \
  --volume-ids vol-0abc1234def567890 \
  --query 'VolumesModifications[*].{State:ModificationState,Progress:Progress}' \
  --output table

Bulk migration with Terraform

resource "aws_ebs_volume" "app_data" {
  availability_zone = "us-east-1a"
  size              = 200          # GB — sized for actual data
  type              = "gp3"
  iops              = 10000        # provisioned independently
  throughput        = 250          # MB/s, independent of IOPS

  tags = {
    Name = "app-data-volume"
  }
}

Required IAM Policy (Least Privilege)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:ModifyVolume",
        "ec2:DescribeVolumes",
        "ec2:DescribeVolumesModifications"
      ],
      "Resource": "*"
    }
  ]
}

Decision Flow: When to Use What

flowchart TD A["New EBS Volume Needed"] --> B{"Legacy system requiring\ngp2 compatibility?"} B -->|"Yes"| C["Use gp2\n(rare edge case)"] B -->|"No"| D{"Need > 3,000 IOPS\nor > 125 MB/s throughput?"} D -->|"No"| E["gp3 at default settings\n3,000 IOPS + 125 MB/s included\nLowest cost"] D -->|"Yes"| F{"Need > 16,000 IOPS\nor > 1,000 MB/s?"} F -->|"Yes"| G["Use io2 Block Express\n(provisioned IOPS SSD)"] F -->|"No"| H["gp3 with provisioned\nIOPS/throughput\nStill cheaper than gp2"] style C fill:#fff3cd,stroke:#ffc107 style E fill:#d4edda,stroke:#28a745 style H fill:#d4edda,stroke:#28a745 style G fill:#cce5ff,stroke:#004085

Glossary

  • IOPS (Input/Output Operations Per Second): The number of read/write operations a storage volume can handle per second; the primary performance metric for databases and transactional workloads.
  • Burst Credits (gp2): A token-bucket mechanism in gp2 where unused IOPS capacity accumulates as credits, allowing temporary performance spikes beyond the baseline — credits deplete under sustained load.
  • Throughput (MB/s): The volume of data transferred per second; critical for sequential workloads like log processing or analytics, distinct from IOPS which measures operation count.
  • Volume Modification: An AWS EC2 feature allowing live changes to EBS volume type, size, IOPS, and throughput without detaching the volume or stopping the instance.
  • Decoupled Scaling: An architectural model where two dimensions (e.g., storage capacity and IOPS) can be adjusted independently, preventing over-provisioning of one resource to satisfy the other.

Comments

Popular posts from this blog

EC2 No Internet Access in Custom VPC: Attaching an Internet Gateway and Fixing Route Tables

Lambda Infinite Loop with S3: How to Break the Recursive Trigger Cycle

IAM User vs. IAM Role: Why Your EC2 Instance Should Never Use a User