Amazon EBS (Elastic Block Store)

EBS provides persistent block storage volumes for EC2 instances. Each volume is automatically replicated within its Availability Zone for durability. EBS volumes are physically attached to EC2 instances via the network (not a shared bus like SAN).

Core Concepts

How EBS Works

EC2 Instance (in AZ us-east-1a)
  └── Network attachment (not local disk)
       └── EBS Volume (in us-east-1a)
            └── File System (ext4, xfs, ntfs)
                 └── Data

EBS is network-attached — not like a local SSD. Latency is ~0.5-2ms vs local NVMe at ~0.1ms. For most applications, this difference is negligible.

Volume Types

TypePerformanceUse CaseCost (per GB/mo)
gp33,000 IOPS, 125 MB/s (base)General purpose, lower cost~$0.08
gp23,000 IOPS burstLegacy general purpose~$0.10
io2256,000 IOPS, 1,000 MB/sHigh-performance databases~$0.125
io2 Block Express256,000 IOPS, 4,000 MB/sUltra-performance~$0.125
st1500 IOPS, 250 MB/sThroughput-intensive (Hadoop, log processing)~$0.045
sc1250 IOPS, 250 MB/sInfrequent access~$0.025

gp3 vs gp2

gp3 is the newer, cheaper option with configurable throughput independent of IOPS:

gp3: 3,000 IOPS + 125 MB/s (base) → configurable up to 16,000 IOPS / 1,000 MB/s
gp2: 3,000 IOPS burst, throughput tied to IOPS

gp3 is ~20% cheaper than gp2 for equivalent performance.

Creating a Volume

# Create a 100GB gp3 volume
aws ec2 create-volume \
  --volume-type gp3 \
  --size 100 \
  --availability-zone us-east-1a \
  --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=my-data-volume}]'

Attaching to EC2

aws ec2 attach-volume \
  --volume-id vol-xxxxx \
  --instance-id i-xxxxx \
  --device /dev/sdf

On the EC2 Instance

# Check available devices
lsblk
 
# Format (first time only)
sudo mkfs.ext4 /dev/sdf
 
# Mount
sudo mount /dev/sdf /mnt/data
 
# Add to /etc/fstab for auto-mount
echo "/dev/sdf /mnt/data ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab

EBS Snapshots

Snapshots are incremental backups stored in S3. First snapshot copies all data; subsequent snapshots only copy changed blocks.

Creating a Snapshot

aws ec2 create-snapshot \
  --volume-id vol-xxxxx \
  --description "pre-migration-backup" \
  --tag-specifications 'ResourceType=snapshot,Tags=[{Key=Name,Value=my-volume-snapshot}]'

Sharing Snapshots

# Make snapshot public (all AWS accounts)
aws ec2 modify-snapshot-attribute \
  --snapshot-id snap-xxxxx \
  --attribute-type createVolumePermission \
  --operation-type add \
  --group-names all
 
# Share with specific account
aws ec2 modify-snapshot-attribute \
  --snapshot-id snap-xxxxx \
  --attribute-type createVolumePermission \
  --operation-type add \
  --user-ids 111122223333

Restoring from Snapshot

# Create volume from snapshot
aws ec2 create-volume \
  --snapshot-id snap-xxxxx \
  --availability-zone us-east-1a
 
# Attach to instance
aws ec2 attach-volume --volume-id vol-yyyyy --instance-id i-xxxxx --device /dev/sdg

Encryption

EBS volumes are encrypted by default (AWS-managed keys). You can also use customer-managed keys (CMK):

# Encrypted volume (default)
aws ec2 create-volume \
  --volume-type gp3 \
  --size 50 \
  --encrypted \
  --kms-key-id arn:aws:kms:us-east-1:123456789012:key/xxxxx

Encryption is transparent — no performance impact. Snapshots of encrypted volumes are also encrypted.

Volume Performance

IOPS and Throughput

gp3: 3,000 IOPS base (configurable to 16,000)
gp2: 3,000 IOPS burst (scales with volume size, 3,000 max)
io2: 256,000 IOPS (Block Express: 256,000)

Volume Size and Performance (gp2/gp3)

gp2 and gp3 IOPS scale with volume size:

  • < 1TB → 3,000 IOPS
  • 1-2TB → 6,000 IOPS
  • 2-3TB → 9,000 IOPS
  • 3-4TB → 12,000 IOPS

For gp3, you can configure IOPS and throughput independently. For gp2, IOPS and throughput are coupled.

Monitoring EBS Performance

# Volume metrics (CloudWatch)
aws cloudwatch get-metric-statistics \
  --namespace AWS/EBS \
  --metric-name VolumeReadOps \
  --start-time 2024-01-15T00:00:00Z \
  --end-time 2024-01-15T12:00:00Z \
  --period 300 \
  --statistics Sum \
  --dimensions Name=VolumeId,Value=vol-xxxxx

Key metrics:

  • VolumeReadOps / VolumeWriteOps — I/O operations
  • VolumeQueueLength — wait time (should be < 10 for good performance)
  • VolumeBurstBalance (gp2 only) — burst IOPS remaining
  • VolumeConsumedReadWriteHours — io2 only

Multi-Attach

io2 volumes can be attached to multiple EC2 instances in the same AZ:

aws ec2 modify-volume \
  --volume-id vol-xxxxx \
  --multi-attach-enabled

Use case: Oracle RAC (shared disk cluster), Windows Scale-Out File Server. Requires a cluster-aware file system (OCFS2, GFS2, AWS FSx).

Instance Store vs EBS

Instance StoreEBS
LocationLocal to host (NVMe)Network attached
Durability0 (ephemeral)99.999% (replicated in AZ)
SizeLimited by instance typeUp to 16TB
PerformanceVery high (0.1ms)High (0.5-2ms)
CostIncluded in instance priceAdditional cost
UseTemporary, non-critical dataPersistent data

Limits

ResourceLimit
Volumes per account5,000 (soft limit)
Max volume size16TB
Max IOPS (gp3)16,000 (independent of size)
Max IOPS (io2 Block Express)256,000
Max throughput (gp3)1,000 MB/s
Snapshots per volumeUnlimited

References

Pricing Examples

Scenario 1: A production database with 500GB gp3 volume + 3,000 IOPS. 500GB × 40/month. Volume usage: 40/month. Plus snapshots: 500GB first snapshot (full) = 0.23/month. Total: ~$64/month.

Scenario 2: A dev environment with 100GB gp3. 100GB × 8/month. Snapshots (30-day retention, 5GB changed each): 5GB × 0.25/month. Total: ~0.10 = $10/month + worse performance.

Nuggets & Gotchas

  • EBS volumes are AZ-locked — you can’t attach a volume from us-east-1a to an instance in us-east-1b: To move a volume between AZs, create a snapshot and restore in the target AZ. To move between regions, copy the snapshot to the target region first.
  • gp2 has a burst bucket — if you exhaust it, IOPS drops to 100: gp2 bursts at 3,000 IOPS for volumes up to 1TB. After burst exhaustion, you get 100 IOPS until the bucket refills (at ~1 IOPS per GB of volume size per minute). Use gp3 for consistent performance or io2 for high IOPS.
  • EBS snapshots are incremental — but deleting a snapshot doesn’t free space if dependent snapshots exist: Only the blocks not referenced by any remaining snapshot are actually deleted. You can’t reduce S3 storage used by snapshots without deleting all dependent snapshots.
  • Volume performance (IOPS/throughput) is measured at the volume level, not the instance level: An m5.xlarge with 2 volumes can achieve up to 6,000 IOPS (3,000 per volume). If you need more IOPS, stripe multiple volumes with LVM or use io2 Block Express.
  • The VolumeBurstBalance metric for gp2 tells you how much burst credit you have remaining: If this drops to 0, your IOPS drops to 100. For production databases, monitor this and consider switching to gp3 (no burst, consistent performance) or io2 (predictable high IOPS).