Replicated network storage vs local NVMe
The oldest storage argument in hosting: local NVMe is fast but dies with the host; network storage survives anything but costs you latency. We put that to a measurement. One identical fio battery, four disks: the local NVMe of a premium Hetzner instance, the local NVMe of a premium DigitalOcean instance, and ServersCamp's two replicated network pools.
Every number below is from a run on 2026-07-18, fio 3.41, one pass, no retries, raw JSON kept for every test. The battery and methodology are published so you can run the same thing on your own machines.
TL;DR
Random IO (the database pattern)
Network storage wins
81 µs QD1 reads vs 112-131 µs on local NVMe 200k read IOPS vs 155-164k 147k fsync'd writes/s vs 96-103k: replicated storage out-committing local disks
Raw sequential and single-writer
Local disks win
Up to 14 GB/s sequential reads on local NVMe vs our 4.3 GB/s tier ceiling 39-56 µs QD1 writes into local write caches A local write cache has no network round trip to pay
The contenders
| Disk | Instance | CPU | Storage under test | Price |
|---|---|---|---|---|
| Hetzner local | CCX23 (dedicated vCPU), 4 vCPU / 16 GB | AMD EPYC-Milan | 160 GB local NVMe (included) | €85.99/mo |
| DigitalOcean local | c5-4vcpu-8gb-intel (CPU-Optimized Premium), 4 vCPU / 8 GB | Intel Xeon Platinum 8358 | 250 GB local NVMe (included) | $161/mo |
| ServersCamp R5 | hf-m (High Frequency), 4 vCPU / 8 GB | AMD EPYC 4565P | 250 GB replicated network NVMe, Basic disk tier 5 | €122.20/mo total (Sustained VM €56 + disk €65.70 + IP) |
| ServersCamp W5 | hf-m (High Frequency), 4 vCPU / 8 GB | AMD EPYC 4565P | 250 GB replicated network NVMe with power-loss protection, Database disk tier 5 | €166.00/mo total (Sustained VM €56 + disk €109.50 + IP) |
Both competitor instances are from their premium dedicated-CPU lines, not budget tiers, and both test their local NVMe: the fastest storage either provider sells at this size. Neither had a network volume attached; this is deliberately the hardest comparison for network storage, their strongest disk against ours. The ServersCamp disks are network-attached and replicated: every write lands on independent storage nodes before it is acknowledged.
Methodology
One battery, 16 tests, 30 seconds each with a 5-second ramp: {4k random, 1M sequential} × {QD1, parallel} × {read, write, 50/50 mixed, fsync'd write}. All tests run with direct=1, ioengine=libaio, on an 8 GiB file on a fresh ext4 filesystem. Parallel means 8 jobs × QD64 for 4k (512 outstanding IOs, enough to saturate a 200k IOPS limit) and 4 jobs × QD16 for sequential, spread across the file with offset_increment.
- This is a buyer-facing benchmark, not a normalized hardware lab test. Each provider was measured on the best comparable instance and storage option it sells in this segment. CPU, hypervisor and IO stack are part of the product, so they are part of the measurement: the thing under test is what a customer VM actually gets.
- Same fio version everywhere (3.41), same battery script, one run per disk, no cherry-picking between runs.
- fsync tests issue
fsyncafter every write: the write-ahead-log pattern of every transactional database. - Raw fio JSON and system info for every test on every machine are preserved and available on request.
4k random, QD1: the latency a query feels
QD1 is one operation at a time, each waiting for the previous: the pattern of index lookups and any chain of dependent reads. This is where storage latency turns directly into application latency.
| 4k QD1 | Hetzner local | DO local | ServersCamp R5 | ServersCamp W5 |
|---|---|---|---|---|
| Random read, avg (p99) | 131 µs (183) | 112 µs (146) | 81 µs (115) | 158 µs (212) |
| Random write, avg (p99) | 56 µs (95) | 39 µs (52) | 65 µs (159) | 144 µs (185) |
| Mixed 50/50, IOPS total | 10 382 | 15 060 | 12 416 | 6 049 |
Reads: the network disk wins outright. 81 µs on a replicated network volume against 112 and 131 µs on local NVMe. The fabric moves data over a direct memory path between machines, and the round trip comes in under the local IO stacks of both premium instances. This is the result that breaks the intuition this article set out to test.
Writes: local caches win, and it is fair to say why. A local NVMe acknowledges a write the moment it lands in the drive's cache, no network involved. Our write is acknowledged after it lands on independent storage nodes. 39 µs versus 65 µs is the price of the copy existing somewhere else, and the fsync section below shows what each of those acknowledgements is actually worth.
4k random, parallel: throughput under load
| 4k, 512 outstanding | Hetzner local | DO local | ServersCamp R5 | ServersCamp W5 |
|---|---|---|---|---|
| Random read IOPS | 155 378 | 164 456 | 199 982 | 188 009 |
| Random write IOPS | 142 326 | 124 020 | 166 696 | 199 617 |
| Mixed 50/50, IOPS total | 155 333 | 136 452 | 183 987 | 196 876 |
Both ServersCamp disks carry a 200 000 IOPS tier limit, and both ran into it: 199 982 reads on R5, 199 617 writes on W5. The limits are enforced by the hypervisor and they are exact; the number on the card is a delivery, and here it is also higher than what either local NVMe produced. The local disks are not throttled at all, this is simply as fast as they went.
fsync: the result we did not expect to win
An fsync'd write is a promise: the data is durable before the call returns. Databases live and die by this pattern; it is also where network storage is supposed to be hopeless, because every promise costs a round trip.
| 4k fsync'd writes | Hetzner local | DO local | ServersCamp R5 | ServersCamp W5 |
|---|---|---|---|---|
| Single writer (QD1), commits/s | 4 643 | 8 826 | 2 398 | 3 560 |
| fsync latency, avg (p99) | 134 µs (440) | 65 µs (239) | 324 µs (643) | 120 µs (420) |
| Parallel writers, commits/s | 96 064 | 102 572 | 70 845 | 147 041 |
A single committer is fastest on DO's local disk: 8 826 durable writes per second at 65 µs per fsync. Our W5 does 3 560. If your workload is one process committing serially, local NVMe is the right tool and this table says so.
Parallel committers flip the table. With multiple writers, the pattern of any real database under load, W5 pushed 147 041 fsync'd writes per second: 1.4x DO's local disk and 1.5x Hetzner's. The Database pool runs on enterprise NVMe with power-loss protection: a flush into protected cache is already durable, so commits complete at full device speed without waiting on media, and the fabric aggregates many writers better than a single local drive. A replicated network disk out-committing the local NVMe of instances costing €86 and $161 is the headline we did not plan for.
1M sequential: bandwidth
| 1M sequential | Hetzner local | DO local | ServersCamp R5 | ServersCamp W5 |
|---|---|---|---|---|
| Read, single stream | 2.28 GB/s | 1.66 GB/s | 3.89 GB/s | 3.89 GB/s* |
| Read, parallel | 9.18 GB/s | 14.18 GB/s | 4.29 GB/s (tier limit) | 4.29 GB/s* |
| Write, single stream | 2.72 GB/s | 2.38 GB/s | 2.04 GB/s | 2.04 GB/s* |
| Write, parallel | 7.45 GB/s | 1.91 GB/s | 2.90 GB/s | 2.90 GB/s* |
Raw parallel bandwidth belongs to the local disks: Hetzner's NVMe streams 9.2 GB/s and DO's reads at a spectacular 14.2 GB/s, while our tier tops out at its advertised 4 GB/s ceiling (which the run hit exactly: 4.29 GB/s measured against a 4 GiB/s limit). Two footnotes worth reading, though: at a single stream, the pattern of one backup or one large file copy, the network disk's 3.89 GB/s beats both locals; and DO's local disk collapses to 1.9 GB/s on parallel writes at 35 ms latency, below even our throttled figure. Fast local reads do not guarantee fast local writes.
Credit where it is due. On these premium lines both providers ship genuinely good disks: tight QD1 tails (p99 146 µs on the c5, 183 µs on the CCX23), six-figure IOPS, and rates that held flat across every 30-second run with no burst-credit cliffs. The numbers look like unshared, visibly un-oversold hardware, exactly what €86 and $161 a month should buy. The budget section below shows how quickly that stops being a given further down the price list.
What the numbers cannot show
- The local disks in this test die with their host. One hardware failure and the 14 GB/s NVMe is a paperweight; recovery is a restore onto new hardware. The ServersCamp volumes are replicated across nodes: a host failure restarts the VM elsewhere with the disk intact, and planned maintenance live-migrates VMs with storage attached.
- The local disks are fixed. 160 GB on the CCX23, 250 GB on the c5. The network volumes resize online and change speed tiers in place, with the data staying put.
- Every ServersCamp figure here is a throttle, not a peak. The same fabric serves higher and lower tiers; you buy the number you need and the hypervisor enforces exactly that.
The budget tier: the same battery on cheap VMs
The premium tier is where providers put their best silicon. The budget tier is where storage corners get cut first, so we ran the identical battery there too.
| Disk | Instance | Storage under test | Price |
|---|---|---|---|
| Hetzner local | CX43 (shared vCPU), 8 vCPU / 16 GB | 160 GB local NVMe | €11.99/mo (a legacy plan we still had; its successors sell at similar money) |
| DigitalOcean local | s-4vcpu-8gb (Basic, Regular CPU), 4 vCPU / 8 GB | 160 GB local NVMe | $48.00/mo |
| ServersCamp R3 | dedicated-l (Basic generation, Sustained), 4 vCPU / 8 GB | 50 GB replicated network NVMe, Basic disk tier 3 | €30.30/mo total |
| ServersCamp W3 | dedicated-l (Basic generation, Sustained), 4 vCPU / 8 GB | 50 GB replicated network NVMe with power-loss protection, Database disk tier 3 | €33.25/mo total |
On Basic-generation hardware the ServersCamp disks are clamped at 50 000 IOPS and 1 GB/s: the real ceiling of what these guests can drive, stated on the card. The competitor budget disks carry no published limits at all, which cuts both ways, as the table shows.
| 4k random | Hetzner CX43 | DO Basic | ServersCamp R3 | ServersCamp W3 |
|---|---|---|---|---|
| QD1 read, avg (p99) | 175 µs (289) | 371 µs (1 970) | 164 µs (247) | 214 µs (268) |
| QD1 write, avg (p99) | 120 µs (208) | 231 µs (1 350) | 150 µs (230) | 190 µs (241) |
| Parallel read IOPS | 56 364 | 33 780 | 49 981 (clamp) | 50 030 (clamp) |
| Parallel write IOPS | 49 335 | 28 524 | 49 981 (clamp) | 49 980 (clamp) |
| QD1 fsync, commits/s | 1 698 | 464 | 1 058 | 2 278 |
| Parallel fsync, commits/s | 10 695 | 16 573 | 42 497 | 46 593 |
| Sequential read / write, parallel | 2.92 / 2.32 GB/s | 3.16 / 1.02 GB/s | 1.07 / 1.07 GB/s (clamp) | 1.07 / 1.07 GB/s (clamp) |
Three things stand out:
- The group-commit gap widens at the bottom. W3 pushed 46 593 parallel fsync'd writes per second against 10 695 on the CX43 and 16 573 on the DO droplet: a 2.8-4.4x lead for the replicated volume with power-loss protection, on the cheapest hardware we sell.
- The clamps held again. 49 981, 49 980 and 50 030 IOPS against a 50 000 limit; 1 074 MB/s against a 1 GiB/s limit. Two tiers, four disks, every limit delivered to a fraction of a percent.
- The $48 droplet trails the €12 legacy box on everything. 371 µs QD1 reads with a p99 near 2 ms, 33k IOPS, 464 single commits per second. Budget-tier storage varies wildly between providers, which is exactly why published limits are worth having.
The cheap VM is not a toy
€30-33 a month buys 4 Sustained vCPUs, 8 GB of RAM and a replicated disk that just did 46 593 durable commits per second. That is a base for a small production system, not a sandbox. And that is the point of the platform: the €2 entry VM exists, but the path upward is not a migration project. You start cheap, switch compute profiles live, retier the disk in place, and keep the same operational model all the way to 200k IOPS on High Frequency hardware.
The verdict: what to pick for what
| Workload | Winner in this test | Why |
|---|---|---|
| Transactional database under real load | ServersCamp W-class | 147k parallel fsync'd commits/s, 1.4-1.5x the local disks, and the disk survives a dead host mid-transaction |
| Read-heavy services, APIs, anything latency-bound | ServersCamp R-class | 81 µs QD1 reads and 200k read IOPS, ahead of both local disks on every read test |
| A single serial writer (one process, one log) | Local NVMe (DO) | 39 µs writes and 8.8k commits/s into a local write cache; nothing over a network matches that round trip |
| Bulk streaming: media processing, large scans | Local NVMe (Hetzner) | 7-14 GB/s of raw sequential bandwidth against our 4 GB/s tier ceiling. Mind DO's 1.9 GB/s parallel-write collapse |
| Anything you cannot afford to lose | Replicated network storage | Every local-disk number in this article is conditional on the host staying alive. The network volumes are not |
The pattern is consistent: local NVMe keeps its two physics advantages, cache-speed single writes and unthrottled sequential streaming. Everything a database does under load, random reads, parallel writes, durable commits, went to the replicated network volumes in this test, on top of the durability they exist for. If your bulk-streaming data is disposable, ServersCamp's answer to that use case is the single-copy Solo disk class, which was not part of this battery.
Reproduce it
The whole battery, complete and copy-pasteable. Each test runs 30 seconds after a 5-second ramp, on an 8 GiB file:
# shared flags
C="--direct=1 --ioengine=libaio --time_based --runtime=30 --ramp_time=5 \
--size=8G --filename=/mnt/bench/fiotest --group_reporting"
# 4k random, QD1
fio --name=4k-qd1-read $C --rw=randread --bs=4k --iodepth=1
fio --name=4k-qd1-write $C --rw=randwrite --bs=4k --iodepth=1
fio --name=4k-qd1-rw $C --rw=randrw --rwmixread=50 --bs=4k --iodepth=1
fio --name=4k-qd1-fsync $C --rw=randwrite --bs=4k --iodepth=1 --fsync=1
# 4k random, parallel (512 outstanding on the IOPS tests)
fio --name=4k-multi-read $C --rw=randread --bs=4k --iodepth=64 --numjobs=8
fio --name=4k-multi-write $C --rw=randwrite --bs=4k --iodepth=64 --numjobs=8
fio --name=4k-multi-rw $C --rw=randrw --rwmixread=50 --bs=4k --iodepth=64 --numjobs=8
fio --name=4k-multi-fsync $C --rw=randwrite --bs=4k --iodepth=64 --numjobs=4 --fsync=1
# 1M sequential, QD1
fio --name=seq-qd1-read $C --rw=read --bs=1M --iodepth=1
fio --name=seq-qd1-write $C --rw=write --bs=1M --iodepth=1
fio --name=seq-qd1-rw $C --rw=rw --rwmixread=50 --bs=1M --iodepth=1
fio --name=seq-qd1-fsync $C --rw=write --bs=1M --iodepth=1 --fsync=1
# 1M sequential, parallel
fio --name=seq-multi-read $C --rw=read --bs=1M --iodepth=16 --numjobs=4 --offset_increment=2G
fio --name=seq-multi-write $C --rw=write --bs=1M --iodepth=16 --numjobs=4 --offset_increment=2G
fio --name=seq-multi-rw $C --rw=rw --rwmixread=50 --bs=1M --iodepth=16 --numjobs=4 --offset_increment=2G
fio --name=seq-multi-fsync $C --rw=write --bs=1M --iodepth=16 --numjobs=4 --offset_increment=2G --fsync=1
Run it on any ServersCamp VM and compare against your current provider. If your numbers on our disks come out below what this page claims, that is a bug: tell us in a ticket.
Disclaimers
- One run per disk, on 2026-07-18. Storage performance varies with fabric load and neighbors; we publish single honest passes, not the best of N.
- Disk sizes differ where the providers fix them (160 GB Hetzner, 250 GB elsewhere). All tests use the same 8 GiB working set, so the size difference does not affect the IO paths measured.
- Both competitor disks are local NVMe, ours are replicated network volumes: a deliberate apples-to-durable-oranges comparison, stated openly. Their network volume products (Hetzner Volumes, DO Volumes) are slower than their local disks and were not attached to these instances.
- Guest CPUs differ (EPYC-Milan, Xeon Platinum 8358, EPYC 4565P), and that is by design, not an apology. At 200k IOPS the guest's silicon and IO stack matter, and each provider sells the stack it sells. A buyer does not get to normalize the CPU out of the VM they paid for; neither did we.
- Prices as shown on the providers' pages on the test date. The ServersCamp totals include the Sustained-profile VM, the disk and a public IP.
- Budget-tier runs used the same battery and fio 3.41 everywhere except the CX43 (CentOS Stream 9, fio 3.35 from its repos). The CX43 is a legacy plan running production-adjacent software; its numbers may flatter or hurt it accordingly.