Marketing pages love big numbers. They shout about "10x faster" and "next-gen storage." But when you deploy a database or a high-traffic API on a new VPS, those marketing claims don't matter. Only the actual throughput does. If your app is slow, you need to know if it's the CPU, the network, or the disk. Specifically, you need to verify the IOPS (Input/Output Operations Per Second) and latency of the underlying storage. NVMe drives can handle millions of IOPS, but your VPS provider might throttle them heavily. Here is how to test the actual performance of your NVMe VPS hosting setup.
Why Raw IOPS Matter More Than Sequential Read
Most people run dd or hdparm to check speed. That measures sequential read/write speed in MB/s. It tells you how fast you can copy a large video file. It tells you almost nothing about how fast your database can handle thousands of small, random requests per second. For heavy applications like PostgreSQL, MySQL, or Node.js apps with high concurrency, random I/O is the bottleneck. NVMe technology shines here because it eliminates the mechanical seek time of HDDs and the queue depth limits of older SATA SSDs. But a VPS is a slice of a larger host. If the host is oversubscribed, your NVMe slice might perform like a cheap SATA SSD. You need to test the random small-block performance to find the truth.
1. Install and Configure FIO
fio is the industry standard for storage benchmarking. It is more flexible and accurate than older tools. Install it via your package manager.
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install fio
# CentOS/RHEL
sudo yum install fio
Ensure you have a test file or directory with enough free space. Do not run these tests on your production data partition if you can avoid it. Create a 4GB file for testing.
dd if=/dev/zero of=/tmp/testfile bs=1M count=4096
2. Test Random Read IOPS (4K Blocks)
This is the most critical test for databases. We want to see how many small reads per second the disk can handle. Use a queue depth (iodepth) of 32 to simulate concurrent requests. Run this for 60 seconds to get a stable average.
fio --name=randread --ioengine=libaio --direct=1 --bs=4k --iodepth=32 --rw=randread --filename=/tmp/testfile --size=4G --numjobs=4 --runtime=60 --group_reporting
Look at the iops line in the output. If you are paying for an NVMe VPS, you should see tens of thousands of IOPS. If you see only a few thousand, your provider is throttling you, or the underlying hardware is not what they claim. Low IOPS here means your database queries will time out under load, regardless of CPU power.
3. Test Random Write IOPS (4K Blocks)
Writes are often slower than reads due to flash wear leveling and journaling. Test random writes with the same parameters.
fio --name=randwrite --ioengine=libaio --direct=1 --bs=4k --iodepth=32 --rw=randwrite --filename=/tmp/testfile --size=4G --numjobs=4 --runtime=60 --group_reporting
Compare this to your read IOPS. A healthy NVMe setup usually has write IOPS close to read IOPS. If writes are significantly lower, check if your filesystem is using heavy journaling. You might need to tune your database's write-ahead log settings to match the storage profile.
4. Check Latency with a High Queue Depth
IOPS is a throughput metric. Latency is the time per operation. High latency kills user experience even if average IOPS look okay. Test with a high queue depth to see how the disk handles pressure. Use --lat_percentiles=1 to get detailed latency breakdowns.
fio --name=latency_test --ioengine=libaio --direct=1 --bs=4k --iodepth=128 --rw=randrw --rwmixread=70 --rwmixwrite=30 --filename=/tmp/testfile --size=4G --numjobs=1 --runtime=60 --group_reporting --percentile_list=99.0:99.9
Look at the clat_ns (completion latency) section. You want the 99th percentile latency to be in the low single-digit milliseconds. If the 99th percentile spikes into the hundreds of milliseconds, your disk is struggling under concurrent load. This is common in shared VPS environments where other tenants are saturating the host's I/O scheduler.
5. Test Sequential Read Speed
For large file serving, backups, or log aggregation, sequential speed matters. Use a larger block size (1MB) and a deep queue.
fio --name=seqread --ioengine=libaio --direct=1 --bs=1M --iodepth=32 --rw=read --filename=/tmp/testfile --size=4G --numjobs=4 --runtime=60 --group_reporting
NVMe drives typically deliver multi-gigabyte per second sequential reads. If you are getting less than 500 MB/s, something is wrong. Check if the VPS network or virtualization layer is bottlenecking the I/O path. This test helps you understand if you can use this VPS for serving large static assets or running backup jobs efficiently.
6. Verify CPU Overhead During I/O
Storage tests don't happen in a vacuum. If your CPU is pegged at 100% during the fio run, the bottleneck might be the virtualization layer, not the disk. Monitor CPU usage while running the random read test.
# Terminal 1: Run the fio test
fio --name=randread --ioengine=libaio --direct=1 --bs=4k --iodepth=32 --rw=randread --filename=/tmp/testfile --size=4G --numjobs=4 --runtime=60 --group_reporting
# Terminal 2: Monitor CPU
htop
If CPU usage spikes to 90-100% on all cores during I/O, your VPS might be under-provisioned for the I/O load. The kernel is spending too much time handling I/O interrupts. In this case, upgrading to a VPS with more CPU cores or a different virtualization type (like KVM vs OpenVZ) might help. OpenVZ containers share the host's kernel and can suffer from I/O scheduling issues that KVM avoids.
7. Test Network-Bound I/O (If Applicable)
If your application relies on remote storage or database connections, local disk speed is only half the story. Test the network latency and throughput to ensure the network isn't the bottleneck. Use iperf3 if you have a second VPS on the same network.
# On server 1
iperf3 -s
# On server 2
iperf3 -c server1_ip -t 60 -P 4
Check the bandwidth and retransmissions. High retransmissions indicate network instability. If your database is on a different server, the network latency will add to your disk latency. For heavy applications, co-locating the database and app on the same VPS or a low-latency network segment is often necessary to avoid network-induced I/O delays.
How to Interpret the Results
Don't just look at the numbers. Compare them to your provider's specifications. If they claim 100,000 IOPS and you get 10,000, you are being throttled. If they claim 10,000 IOPS and you get 12,000, you are getting a good deal. Always check the block size. A provider might advertise high IOPS for 128K blocks, which is much easier to achieve than 4K blocks. Your database uses 4K blocks. Always test with the block size your application actually uses.
Also, consider the consistency. A disk that averages 50,000 IOPS but spikes to 500ms latency once every 10 seconds is worse than a disk that consistently delivers 30,000 IOPS with 2ms latency. Consistency is key for user-facing applications. Use the percentile data from test #4 to judge consistency.
When to Upgrade or Change Providers
If your IOPS are consistently below your application's requirements, upgrading the VPS plan might help. Look for plans that offer dedicated IOPS or NVMe storage without shared throttling. If the host is oversubscribed, no amount of CPU upgrade will fix the I/O bottleneck. In that case, consider switching to a provider with better I/O isolation. Dedicated IOPS guarantees are worth the premium for database-heavy workloads.
What to Check First
Start with the 4K random read test. This is the most common bottleneck for web applications. If that passes, check the latency percentiles. If latency is high, your provider is likely oversubscribing the storage. If both IOPS and latency are good, your performance issues are likely in the application code, database indexing, or network configuration. Always test under realistic load. A single fio run is a snapshot. Run tests during peak hours to see if performance degrades due to neighbor noise. NVMe VPS hosting is fast, but only if the provider doesn't throttle it. Verify your numbers before you commit to a long-term contract.
