₹200 free credit when you verify after signup, plus your first recharge doubled. Terms
Engineering blog

We benchmarked our own 4 vCPU cloud VM in public: NVMe-backed Ceph, raw data included

By Geet Mangal, Founder and CTO · Published · Updated · 7 min read

Most VPS benchmark posts show one big IOPS number, from one run, on a machine you cannot rent. We did it the other way. We wrote an open-source benchmark suite, ran it three times on an ordinary BookMyHost cloud VM, and put every raw fio, sysbench and iperf3 file on GitHub. You can rerun every number here on your own server, or on ours.

This post leads with what our storage is good at: throughput under parallel load and consistency over time. It also shows plainly where it is slower than a single local NVMe drive, and why we built it that way.

The setup

VM 4 vCPU / 8 GB RAM, Ubuntu 24.04 LTS, KVM on Apache CloudStack
CPU Intel Xeon (Cascade Lake) as presented by KVM, 4 vCPU
Disk 20 GB root volume, Ceph RBD on an erasure-coded 3+1 pool over Micron 7400 NVMe (network block storage, not local NVMe)
Zone Noida, India
When 25 Oct 2026, three back-to-back runs, 21:35 to 22:18 IST (Sunday evening)
Tools fio 3.36, sysbench 1.0.20, iperf3 3.16
Profile standard: 4 GiB test file, 60 s per fio job, 4 jobs for random IO, 2 jobs at QD16 for sequential

Every number below is the median of three separate runs. The run-to-run table is in the raw data.

Headline results

Metric Median of 3 runs Run-to-run range
4k random read IOPS, QD32 x 4 jobs 80,088 77,403 to 82,186
4k random write IOPS, QD32 x 4 jobs 19,839 19,561 to 20,667
4k mixed 70/30 IOPS, QD32 x 4 jobs 41,406 40,807 to 42,417
1M sequential read 4,026 MB/s 3,992 to 4,073 MB/s
1M sequential write 1,822 MB/s 1,715 to 2,002 MB/s
CPU steal during the 60 s probe 0.00 % avg (max 0.00 %)
sysbench CPU, 1 thread / 4 threads 514.9 / 2,051 events/s (3.97x scaling)
iperf3 VM to VM, same zone, 4 streams 191.1 up / 190.9 down Mbit/s

Throughput under parallel load

With four jobs at queue depth 32, the VM read 80,088 random 4k blocks per second and wrote 19,839. That is the load a busy database, a CI runner or a container host generates: many requests in flight at once. Ceph spreads them over every NVMe drive in the pool, so parallel IO scales across drives instead of queuing behind one. Sequential 1 MiB reads reached 4,026 MB/s and writes 1,822 MB/s, which matters for backups, restores and media.

Writes cost more than reads on erasure-coded storage. Each 4k write becomes three data chunks plus one parity chunk on four different hosts, so random write IOPS are roughly a quarter of random reads. We think that is the honest price of not losing data when a drive dies.

Consistency: the noisy-neighbour probe

A benchmark that runs for 15 seconds can hit a quiet moment. The suite ends with a 60 second probe that records CPU steal every second and a 4k QD1 read latency sample every 10 seconds.

  • CPU steal: 0.00 % on average, 0.00 % at the worst second. Above about 2 % sustained, a VM's CPU numbers stop meaning much. We were nowhere near it.
  • Latency spread: the QD1 read p99 across the probe samples stayed within 1.09x (p99 between 1,761 and 1,958 us). A spread above 2x usually means a neighbour is hammering the same disks.
  • Run to run: across the three full runs, the QD32 random read result moved 77,403 to 82,186.

CPU thread scaling

sysbench prime search scored 514.9 events/s on one thread and 2,051 on four, a 3.97x scaling on four vCPUs. Scaling well below the vCPU count hints that the "cores" share physical threads with someone else under load. Memory bandwidth for a single thread was 25,190 MiB/s read and 22,423 MiB/s write.

Network: iperf3 between two VMs

We ran an iperf3 server on a second VM in the same zone and pushed 4 parallel TCP streams for 10 s in each direction: 191.1 Mbit/s up and 190.9 Mbit/s down, with 0.33 ms average ping between them. This is VM to VM inside one zone, not internet throughput. It sits right at the 200 Mbit/s per-VM throttle that applied to this test offering (CloudStack's vm.network.throttling.rate of 200 Mbit/s, because the test offering sets no rate of its own), so it measures the shaping limit, not the fabric.

Where local NVMe is faster, and why we accept it

Here are the numbers a local-NVMe VPS will beat us on. We are publishing them anyway.

Metric Median What a local NVMe VPS typically shows
4k random read, QD1, 1 job 934 IOPS several thousand to 10,000+ IOPS
4k random write, QD1, 1 job 476 IOPS several thousand IOPS
4k read latency p50 / p99 / p99.9, QD1 1,036 / 1,810 / 3,719 us under 100 us p50
4k write with fsync=1, p50 / p99 5,472 / 8,225 us under 1 ms

A local NVMe drive answers a single 4k read in well under 100 microseconds. On our storage, the same read crosses the network to the host that holds the object, and a durable write waits until enough chunks have landed on enough hosts. That round trip is why a single-threaded app that does one IO at a time (QD1), or a database that fsyncs every commit, sees about a millisecond or more per operation instead of a fraction of one.

What you get for that latency:

  • A dead drive or a dead host does not take your VM down or lose your data. The EC 3+1 pool rebuilds from the surviving chunks.
  • Live migration. We can move your running VM off a host for maintenance or a hardware fault without a reboot, because the disk is not tied to that host.
  • Throughput that grows with the cluster, as the QD32 numbers show, instead of the ceiling of one drive.

If your workload is a single-threaded, fsync-heavy database on one VM and you handle replication yourself, a local-NVMe host will be faster per commit. For most web apps, APIs, CI and container workloads, which run many IOs in parallel, the parallel numbers above are the ones you feel, and you keep your data when hardware fails.

Methodology

  • fio with --direct=1 (bypasses the guest page cache), ioengine=libaio, time-based 60 s jobs on a 4 GiB file pre-filled with real data, so thin-provisioned zero blocks cannot inflate reads.
  • Tests: 4k random read and write at QD1 and QD32 x 4 jobs, 70/30 mixed, 64k and 1M sequential at QD16 x 2 jobs, a dedicated QD1 latency test with lat_percentiles, and a 4k write with fsync=1.
  • sysbench CPU (--cpu-max-prime=20000, 1 and 4 threads) and memory (1 MiB blocks, 1 thread), openssl AES-256-GCM, a pure-Python loop.
  • iperf3, 4 streams, 10 s each way, to a second VM in the same zone. Ping to 1.1.1.1 and HTTPS TTFB to public sites.
  • A 60 s noisy-neighbour probe: steal % every second, fio QD1 sample every 10 s.
  • Three separate runs on a fresh VM with nothing else running; every published number is the median across runs (report.py median).
  • The VMs were temporary and destroyed after the run.

Full details, including VM caveats like steal, ballooning, burst credits and thin provisioning: docs/methodology.md.

Reproduce it

sudo apt-get install -y fio sysbench iperf3 jq
git clone https://github.com/geetmangal/bmh-nvme-bench && cd bmh-nvme-bench
# optional: start "iperf3 -s" on a second machine in the same region
for i in 1 2 3; do
  ./bench.sh --profile standard --no-prompt --label my-vps-4c8g --iperf-server <server-ip> --target $HOME/bench-tmp
done
python3 report.py median results/my-vps-4c8g-* --out results/my-vps-median
python3 report.py compare data/2026-10-25-bmh-noida-standard/median results/my-vps-median --labels BookMyHost,MyVPS

How other providers compare

Placeholder, to be filled from the competitor trial runs (see docs/comparison-runbook.md in the repo). Same standard profile, Ubuntu 24.04, 4 vCPU / 8 GB, region nearest India, three runs, median, raw data published.

Metric BookMyHost (Noida) Provider A Provider B Provider C
4k random read IOPS, QD32 80,088 TBD TBD TBD
4k random write IOPS, QD32 19,839 TBD TBD TBD
1M sequential read MB/s 4,026 TBD TBD TBD
1M sequential write MB/s 1,822 TBD TBD TBD
4k read p99, QD1 (us) 1,810 TBD TBD TBD
fsync write p99 (us) 8,225 TBD TBD TBD
CPU steal avg % 0.00 TBD TBD TBD
sysbench 4-thread events/s 2,051 TBD TBD TBD
Storage type Ceph EC 3+1 on NVMe (network) TBD TBD TBD
Monthly price (INR) TBD TBD TBD TBD

FAQ

How many IOPS does a BookMyHost 4 vCPU / 8 GB VM get? 80,088 4k random read and 19,839 4k random write IOPS at QD32 x 4 jobs, median of three runs on 25 Oct 2026.

Is the disk local NVMe? No. It is Ceph RBD on an erasure-coded 3+1 pool over Micron 7400 NVMe drives: network block storage that survives a drive or host failure and allows live migration.

Why are QD1 and fsync latency higher than on some VPS hosts? Each IO crosses the network, and each durable write lands on several hosts before it is acknowledged. That is the cost of redundancy; parallel throughput is where the design pays back.

Can I run the same benchmark? Yes: the suite is MIT licensed, and the commands are above.

Did you test other providers? Not yet. Those runs are planned with the same rules, and this post will be updated with their raw data.

Repository · Raw benchmark data

FAQ

Questions on this post

How many IOPS does a BookMyHost 4 vCPU / 8 GB VM get?

In our 25 Oct 2026 run (median of three standard-profile runs) the VM did 80,088 4k random read IOPS and 19,839 4k random write IOPS at queue depth 32 with 4 jobs, measured with fio direct=1 on a pre-filled 4 GiB file.

Is the disk local NVMe?

No. The VM disk is a Ceph RBD image on an erasure-coded 3+1 pool built on Micron 7400 NVMe drives across several hosts. It is network block storage, so it survives a drive or host failure and allows live migration, but single-IO latency is higher than a local NVMe drive.

Why is QD1 and fsync latency higher than on some cheaper VPS hosts?

Every write is split into data and parity chunks and sent over the network to several hosts before it is acknowledged. A local NVMe drive answers in tens of microseconds; replicated network storage needs a network round trip, so QD1 reads take about 1,036 us and a durable fsync about 5,472 us at the median.

Can I run the same benchmark on my own server?

Yes. The suite is open source (MIT). Clone github.com/geetmangal/bmh-nvme-bench, run ./bench.sh --profile standard, and render the results with python3 report.py. It needs fio, sysbench, iperf3 and jq.

Did you test other providers?

Not yet. Competitor runs on free-trial or hourly-billed VMs are planned with the same profile, OS and rules, and this post will be updated with the numbers and raw data.

Run it on hourly billing

NVMe cloud servers in India, resize in place, GST invoice either way. Every new account starts with ₹200 of free credit.

Build a server
WhatsApp