NVMe vs SATA SSD on a VPS: benchmarks from our own fleet
Real fio numbers from production nodes, why IOPS marketing is mostly noise, and how to tell whether your disk is actually the bottleneck.
Marek Lindqvist
Infrastructure Security
Published
Test methodology
Run on production nodes in Frankfurt during a low-traffic window, from inside a 4 vCPU / 8 GB guest, so these are numbers a customer could reproduce โ not host-level figures with the guest overhead removed.
fio --name=randread --ioengine=libaio --direct=1 --bs=4k \
--iodepth=32 --size=4G --runtime=60 --numjobs=4 --group_reporting --rw=randread
4K random read, QD32
| Storage | IOPS | Bandwidth | Avg latency | p99 latency |
|---|---|---|---|---|
| NVMe RAID-10 (current) | 287,000 | 1,121 MB/s | 0.11 ms | 0.38 ms |
| SATA SSD RAID-10 (retired 2023) | 43,200 | 169 MB/s | 0.74 ms | 3.10 ms |
| Network block storage (typical cloud) | 16,000* | 62 MB/s | 1.90 ms | 11.4 ms |
* Capped by the provider's per-volume IOPS limit, not by the hardware.
4K random write, QD32
| Storage | IOPS | Avg latency | p99 latency |
|---|---|---|---|
| NVMe RAID-10 | 168,000 | 0.19 ms | 0.71 ms |
| SATA SSD RAID-10 | 31,500 | 1.02 ms | 5.80 ms |
What that means in workload terms
- PostgreSQL, 8 GB dataset, pgbench 50 clients: 4,180 tps on NVMe vs 940 tps on SATA. The database is latency-bound on WAL flushes, which is exactly NVMe's strength.
- Windows Server boot to usable desktop: 19 s vs 41 s. Not important once, very noticeable when you reinstall or reboot regularly.
- npm install on a large monorepo: 47 s vs 112 s. Package managers are a flood of tiny random writes.
- Serving static files from nginx: essentially identical. Once the working set is in page cache, the disk is irrelevant โ do not pay for NVMe to solve a problem you do not have.
Why "1,000,000 IOPS" in an ad means nothing
Three reasons that number is usually theatre:
- It is the node's total, not yours. A node hosting 40 guests shares that pool. Your share depends entirely on what the neighbours are doing.
- It is a burst figure. Consumer-class NVMe uses an SLC cache; once it is full, sustained write speed can fall by 70%. Enterprise drives with power-loss protection hold their numbers, and cost about 3x more per terabyte.
- Queue depth is unstated. QD256 with 16 jobs produces a big number that no real application generates.
The honest metric is p99 latency under a realistic queue depth, sustained for at least ten minutes. That is why the tables above include p99.
Is your disk actually the bottleneck?
Linux
iostat -xz 1 # %util near 100 with high await = disk-bound
vmstat 1 # high 'wa' in the CPU columns = waiting on I/O
iotop -oPa # which process is responsible
Windows
Get-Counter '\PhysicalDisk(_Total)\Avg. Disk sec/Read' -Continuous
# Sustained above 0.020 s (20 ms) means the disk is the constraint.
If await is low and %util is low but the app is still slow, the disk is innocent โ look at CPU steal, memory pressure or a network round trip.
What we run
Every RDPForge node uses enterprise NVMe (Samsung PM9A3 / Micron 7450 class) in RAID-10 with power-loss protection and hardware-accelerated parity. There is no SATA tier left in the fleet โ the last SATA node was retired in November 2023 โ and there is no network-attached block storage anywhere, so your disk is always physically in the machine running your VM.
Marek Lindqvist
Infrastructure Security
Runs our hardening baselines and incident response. Previously a network engineer at a Nordic transit provider.
Put this into practice for $5 a month
Windows RDP from $12/month, Linux VPS from $5/month, delivered in about four minutes with a 72-hour money-back guarantee.