Overview
IOPS (input/output operations per second) is the number of read and write operations a disk can complete each second. It's the storage metric that matters most for databases and other random-access workloads, and the one most often sized by guesswork.
This guide applies to any virtualization platform or cloud provider: how IOPS relates to throughput and latency, what typical workloads need, what different media can deliver, and how to measure and limit IOPS properly.
IOPS, Throughput and Latency
The three storage metrics are linked, and quoting one without the others is meaningless.
- IOPS: operations per second.
- Throughput: bytes per second, which is IOPS × block size.
- Latency: how long a single operation takes, usually in milliseconds or microseconds.
The same disk can show very different IOPS depending on block size: 10,000 IOPS at 4 KiB is about 40 MiB/s, while at 128 KiB it's about 1.25 GiB/s, which most disks can't sustain. A vendor IOPS figure without a block size, a read/write mix and a queue depth tells you very little.
Queue depth is the number of operations in flight at once. Fast storage, NVMe in particular, only reaches its rated IOPS with many parallel requests. A single-threaded application waiting for each write to finish sees latency, not rated IOPS.
Typical Workload Profiles
These are starting points for sizing a single VM's disk, not guarantees. Measure your own workload (see below) before committing.
| Workload | Typical IOPS | Pattern | | ----------------------------------------- | ------------- | ------------------------------------------ | | Static website, small app server | 100–500 | Mostly reads, served largely from cache | | CMS or web app with moderate traffic | 500–2,000 | Mixed random reads and writes | | Medium OLTP database (PostgreSQL, MySQL) | 2,000–10,000 | Random 8–16 KiB reads and writes, fsync-heavy | | Busy database, message broker, search | 10,000+ | Random I/O at high queue depth; latency-sensitive | | Logging, backups, analytics scans | Low IOPS | Large sequential I/O; size by throughput instead |
What Storage Media Can Deliver
Approximate random 4 KiB performance per device:
| Media | Random IOPS (approx.) | Typical latency | | ----------------------------- | ----------------------- | --------------- | | 7,200 rpm HDD | 75–150 | 5–15 ms | | 10–15k rpm SAS HDD | 150–250 | 3–6 ms | | SATA SSD | Tens of thousands | ~0.1 ms | | NVMe SSD | Hundreds of thousands+ | Tens of µs | | Network block storage (iSCSI, Ceph, cloud volumes) | Depends on backend and network | Adds network round-trips |
Network storage adds latency on every operation, and its real limit is often the network or the storage cluster's total capacity rather than the disks behind it.
RAID Write Penalty
Writes on parity RAID cost more than one backend operation each, so usable write IOPS is lower than the sum of the disks:
| RAID level | Backend operations per write | Effect | | ---------- | ---------------------------- | ------------------------------------------ | | RAID 0 | 1 | Full speed, no redundancy | | RAID 1/10 | 2 | Good write performance; the usual choice for databases | | RAID 5 | 4 | Read-modify-write of data and parity | | RAID 6 | 6 | Two parity blocks |
Usable write IOPS ≈ (disks × IOPS per disk) ÷ write penalty. Eight HDDs at 150 IOPS each give about 600 write IOPS in RAID 10, and only about 200 in RAID 6.
Sizing Method
- Measure the existing workload. On Linux,
iostat -x 5shows reads/s (r/s), writes/s (w/s), average latency (r_await,w_await) and utilisation per device. Collect data across a full business cycle, including month-end jobs and backups. - Size for the peak, not the average. A database averaging 500 IOPS that hits 4,000 during a nightly batch needs 4,000.
- Add headroom. 30–50% above the measured peak absorbs growth and short bursts.
- Check the whole path. A VM disk can't be faster than the slowest of its virtual disk limit, the host's storage, the network to shared storage, and the storage backend's total capacity shared across all VMs.
Limiting IOPS per VM
On shared storage, one busy VM can consume the whole backend's capacity and slow every other VM down (the "noisy neighbour" problem). Most hypervisors and cloud platforms let you cap IOPS and throughput per virtual disk.
- Set limits on shared storage, especially in multi-tenant environments.
- Allow bursts where the platform supports it: a higher limit for short periods covers boot storms and batch jobs without raising the sustained cap.
- Limit both IOPS and throughput. An IOPS cap alone still lets large-block sequential I/O saturate the backend.
- Don't cap latency-critical databases too tightly. Size their limits from measured peaks, or give them dedicated storage.
Measuring with fio
fio is the standard tool for storage benchmarking. Always test with direct I/O, so you measure the disk rather than the page cache.
bash1# Random 4 KiB read IOPS at queue depth 32 2fio --name=randread --filename=/data/fio.test --size=4G \ 3 --rw=randread --bs=4k --iodepth=32 --numjobs=4 \ 4 --ioengine=libaio --direct=1 --runtime=60 --time_based --group_reporting 5 6# Database-like mix: 70% reads, 30% writes, 8 KiB blocks 7fio --name=oltp --filename=/data/fio.test --size=4G \ 8 --rw=randrw --rwmixread=70 --bs=8k --iodepth=16 --numjobs=4 \ 9 --ioengine=libaio --direct=1 --runtime=60 --time_based --group_reporting 10 11# Single-threaded synchronous writes: what a database commit actually feels 12fio --name=fsync --filename=/data/fio.test --size=1G \ 13 --rw=write --bs=4k --iodepth=1 --fsync=1 \ 14 --ioengine=sync --runtime=30 --time_based
In the output, look at IOPS, the latency percentiles (clat p99 and p99.9), and whether results stay stable over the run.
Summary
- Quote IOPS together with block size, read/write mix and queue depth.
- Size from measured peaks plus headroom, not from averages or rules of thumb.
- Account for RAID write penalties and network storage latency.
- Cap IOPS and throughput per VM on shared storage to contain noisy neighbours.
- Benchmark with
fioand direct I/O, and judge results by latency percentiles as well as IOPS.