Slow storage shows up as high load averages, slow database queries and sluggish deployments, even when the CPU is idle. The fix starts with measuring properly: what kind of I/O the workload does, and what the disk can deliver.

Know the numbers that matter

  • IOPS — operations per second. Databases and many small files depend on random-read/write IOPS.
  • Throughput (MB/s) — matters for large sequential files: backups, media, logs.
  • Latency — how long each operation takes. Often the most important number for interactive workloads.
  • Queue depth — how many operations are in flight. SSDs and NVMe deliver their best IOPS with parallel requests.

Benchmark with fio

dd only measures one simple pattern. fio lets you test realistic patterns. Run tests in a directory on the disk you’re measuring, with files larger than RAM caching can hide (or use --direct=1):

apt install -y fio
mkdir -p /root/fio && cd /root/fio

# Random 4K reads (database-like)
fio --name=randread --rw=randread --bs=4k --size=2G --iodepth=32 \
    --ioengine=libaio --direct=1 --runtime=60 --time_based --group_reporting

# Random 4K writes
fio --name=randwrite --rw=randwrite --bs=4k --size=2G --iodepth=32 \
    --ioengine=libaio --direct=1 --runtime=60 --time_based --group_reporting

# Sequential 1M reads (backup/media-like)
fio --name=seqread --rw=read --bs=1M --size=2G --iodepth=8 \
    --ioengine=libaio --direct=1 --runtime=60 --time_based --group_reporting

Look at IOPS, BW and the latency percentiles (clat percentiles, especially 99th). Delete the test files afterwards.

On shared infrastructure such as a VPS, results vary over time — run tests a few times and compare averages.

Watch live I/O

iostat -xz 1
Column Meaning
r/s, w/s Reads and writes per second
rkB/s, wkB/s Throughput
r_await, w_await Average latency in ms (including queue time)
aqu-sz Average queue length
%util Time the device was busy — on SSDs, 100% doesn’t always mean saturated

Find the processes responsible:

iotop -oPa          # accumulated I/O per process
pidstat -d 1        # from sysstat

Tuning checklist

Mount options

Add noatime to data filesystems in /etc/fstab so reads don’t trigger metadata writes:

UUID=…  /var/lib/mysql  ext4  defaults,noatime  0 2

I/O scheduler

cat /sys/block/vda/queue/scheduler

For SSD/NVMe and virtual disks, none or mq-deadline is usually best. Change temporarily with echo mq-deadline > /sys/block/vda/queue/scheduler, or permanently with a udev rule.

Filesystem choice

ext4 and XFS are both excellent. XFS handles large files and parallel writes well; ext4 is a safe default. The difference is small compared with application-level changes.

Reduce the writes

The best I/O is the one you don’t do:

  • Cache — a page cache in front of your web app, Redis for sessions and object caching.
  • Database memory — a large enough InnoDB buffer pool or PostgreSQL shared_buffers turns disk reads into memory reads.
  • Log less — disable access logs for static assets, buffer logs, rotate and compress.
  • Batch writes — group many small writes into fewer, larger ones in your application.

Writeback tuning

On servers with lots of RAM, limiting dirty memory smooths out write bursts — see Linux disk caching.

When it’s the hardware

If latency is high even with low utilization from your own processes, or %steal CPU time is high in top on a VPS, the bottleneck may be outside your server. Check with your provider, and consider whether your workload needs a larger plan or a dedicated server with its own disks.

Summary

Measure with fio and iostat, find heavy processes with iotop, then reduce I/O through caching and memory before tuning kernel settings. More tuning in Linux server performance. For data-heavy projects, our Storage VPS offers large SSD capacity.

  • Linux
  • Performance
  • Storage