CPU, memory, and storage

Diagnose storage latency

Separate filesystem capacity from block-device latency, queueing, throughput, and application sync behavior.

8 minute lesson

~~~

A filesystem can have free space while storage latency makes every request slow. df -h says 60% free, the app times out anyway, and everyone is confused. Capacity and speed are different problems.

The symptom pattern: requests slow down across the board, load average climbs, but CPU sits mostly idle with high I/O wait. That combination says “storage,” and the next job is finding which device and which process.

Measure the device

iostat -xz 5 3
Device   r/s    w/s   rkB/s   wkB/s  r_await  w_await  aqu-sz  %util
sda     2.1   312.4    84.2  48120.5     3.1    187.4    18.2   99.6

Skip the first sample — it’s the average since boot, not the current state. Then read three fields. r_await and w_await are the average milliseconds each read or write waits, queue time included: single-digit values are fine for SSDs, and 187ms per write is a disaster. aqu-sz is the average queue depth — 18 requests waiting means work arrives much faster than the device completes it. %util near 100 says the device was busy the whole interval.

Map the busy device to what’s mounted on it:

findmnt -o TARGET,SOURCE,FSTYPE /dev/sda1
# /var  /dev/sda1  ext4

Find the process creating the work

I/O wait needs context: it can coexist with idle CPUs and does not identify the responsible process alone. pidstat -d does:

pidstat -d 5 2
      UID       PID   kB_rd/s   kB_wr/s  Command
      998      4110      0.00  46210.30  pg_dump
     1001      2143     12.40     88.10  node

There’s the answer: a backup job writing 46 MB/s to the same disk the application lives on. The fix isn’t faster hardware, it’s moving the backup window, throttling it with ionice, or pointing it at a different volume.

Confirm from the application side too — database slow-query logs or request timing should improve the moment the writer stops. Capture device samples during a known read or write, and match the busy device to its mount and the process creating work.

The trap is trusting %util on SSDs and NVMe. Those devices serve many requests in parallel, so “100% busy” can still mean plenty of spare capacity. On modern flash, judge saturation by await climbing and aqu-sz growing, not by the utilization column.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →