io1 and io2 EBS volumes using under half their provisioned IOPS over 30 days
What does ZopNight detect here?
ZopNight flags `io1` and `io2` EBS volumes that averaged under 50% of their provisioned IOPS over 30 days and never peaked at 80% or more. It recommends cutting provisioned IOPS by 25%, never below 3,000, and prices the saving at the AWS per-IOPS rates, $0.065 per IOPS-month for io1 in us-east-1.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-075 |
| Category | rightsizing |
| Severity | low |
| Metric | provisioned IOPS utilisation |
| Threshold | < 50% average, peak < 80% |
| Evaluation window | 30d |
| Source | ZopNight |
| Permissions used | ec2:DescribeVolumes · cloudwatch:GetMetricStatistics |
Where it applies
Provisioned IOPS are billed whether you use them or not
On io1 and io2 volumes you pay for storage and, separately, for every IOPS you provision, each month, however busy the volume is. The EBS price data for US East (N. Virginia) lists $0.065 per IOPS-month for io1. io2 is tiered: $0.065 per IOPS-month for the first tier, $0.0455 for the second and $0.03185 for the third. A 20,000 IOPS io1 volume therefore carries $1,300 a month in IOPS charges before storage.
These volumes are sized for the worst day, and the worst day often never arrives. AWS positions Provisioned IOPS SSD volumes for sustained, latency-sensitive I/O, which is exactly the workload teams over-provision to be safe.
Comparing IOPS used with IOPS provisioned
aws ec2 describe-volumes --filters Name=volume-type,Values=io1,io2 \ --query 'Volumes[].[VolumeId,VolumeType,Size,Iops]' --output table
aws cloudwatch get-metric-statistics --namespace AWS/EBS \ --metric-name VolumeWriteOps --dimensions Name=VolumeId,Value=vol-0123456789abcdef0 \ --statistics Sum --period 3600 \ --start-time 2026-08-26T00:00:00Z --end-time 2026-09-25T00:00:00ZRepeat with VolumeReadOps, add the two and divide by 3,600 to get the average IOPS for each hour. On Nitro
instances VolumeAvgIOPS
reports the average directly.
Utilisation tests before a cut is suggested
- The volume type is
io1orio2and its provisioned IOPS are known and above 3,000. - ZopNight has a provisioned-IOPS utilisation series for the volume, averaged over the last 30 days. Without it there is no recommendation; the rule never cuts blind.
- Average utilisation is below 50% and the highest reading in the full series is below 80%, so a volume that is quiet on average but spikes keeps its headroom.
- A monthly cost is known for the volume.
Volumes protected from a cut
Names that mark a standby, replica, failover, disaster-recovery or backup role are skipped, as are volumes identified as databases, message brokers or search clusters. Those workloads can go from idle to full load in seconds. A volume already at or below 3,000 IOPS has no safe reduction.
Pricing a 25% IOPS reduction
target IOPS = current IOPS - 25%, never below 3,000saving = IOPS cost at current level - IOPS cost at target levelIOPS cost follows AWS’s per-IOPS rates, including the io2 tiers. When the volume’s billed cost is lower than the list-price IOPS cost, because of a discount, the saving is scaled to the billed figure, then kept between zero and the volume’s cost. The 25% step is deliberately fixed: repeated runs move a volume down gradually rather than sizing it to one month’s peak.
Lowering provisioned IOPS
- Check the volume’s peak IOPS and queue length over a longer period than 30 days if you have it.
- Apply the recommended value:
aws ec2 modify-volume --volume-id vol-0123456789abcdef0 --iops 15000 - Watch latency and
VolumeQueueLengthfor a few days before any further cut. - If the volume needs 80,000 IOPS or fewer, the gp3 maximum, compare the cost of moving it to gp3 instead.