Resource Troubleshooting
"The server has gotten slow" is a complaint that can trace back to four entirely different causes: not enough CPU, RAM running out, disk I/O saturation, or a full disk. Process Monitoring and Process Memory already covered CPU and memory in depth at the level of a single process, and Disk and File System Basics covered disk capacity. But when a problem actually shows up, the first question is different: "which of these four is it?" This article is about exactly that first, fast triage step — comparing CPU, memory, and disk with one unified view, then moving into a deep dive on whichever resource turns out to be the culprit.
Why One Tool Isn't Enough
top shows CPU and memory together, but tells you almost nothing about disk I/O. free only covers memory. df only covers disk capacity. If the actual problem is disk speed and you only check top, CPU and memory can look completely normal — and time gets wasted looking in the wrong place. That's why the first triage step should always be a tool that shows all resources at once.
vmstat: Four Resources on One Screen
This prints statistics every 2 seconds, 5 times total:
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 3400200 812400 2200800 0 0 12 30 140 310 8 3 88 1 0
6 4 0 3398100 812400 2201900 0 0 1840 2200 310 520 10 6 40 44 0
The columns fall into four groups:
| Group | Column | Meaning |
|---|---|---|
| procs | r |
Number of runnable processes waiting for CPU |
b |
Number of processes in uninterruptible sleep, typically waiting on disk I/O | |
| memory | free |
Free RAM, in KiB |
buff/cache |
Memory used for disk caching — the same buff/cache seen in Process Memory |
|
| swap | si/so |
Amount swapped in/out per second |
| io | bi/bo |
Blocks read from/written to disk per second |
| cpu | us/sy |
Percentage of CPU spent on user-space and kernel code |
wa |
Percentage of time the CPU sat idle waiting for disk I/O to complete |
The second row paints a completely different picture from the first: both r (6) and b (4) are elevated, and wa is 44 — this means the CPU itself is not busy (us+sy = 16), but is instead sitting idle waiting for the disk to respond.
Info
wa (I/O wait) is one of the most frequently overlooked columns in troubleshooting. High wa combined with low us/sy almost always points to slow disks, a network file system (NFS), or a saturated disk — not a CPU problem.
Interview angle
A related trap interviewers like to probe: a large amount of used swap by itself does not mean a system is in trouble. What matters is si/so — if both sit near zero while swpd shows a large used value, it usually means cold pages were pushed out once, a while ago, and are simply sitting there unused; the system is not actively thrashing. Active swap thrashing shows up as ongoing, nonzero si/so, not as a static swpd number. This distinction is covered in more depth in Process Memory.
Load Average: the First Number, and What It Hides
Before vmstat, the fastest single glance is the load average — the three numbers uptime (and top) show for the last 1, 5, and 15 minutes:
Two things make this number widely misread:
- It is relative to core count. A load of
7.82is saturation on a 4-core box but comfortable on a 16-core one — always divide by the output ofnproc. The rising trend here (7.82 over 1 min vs 2.05 over 15 min) says the pressure is recent and growing, which is often more useful than the absolute value. - On Linux it counts more than CPU. Unlike most other Unixes, Linux load includes processes in uninterruptible sleep (
Dstate, waiting on I/O), not just those waiting for CPU. That is why a machine with idle CPUs can still show a load of 8 — the same disk-bound situation thebandwacolumns ofvmstatreveal. A high load with lowus/syis the signature of an I/O problem, not a CPU one.
In short, load average tells you that the system is under pressure and how it is trending; vmstat is still what tells you which resource is responsible.
Which Resource to Check First: A Decision Table
A single vmstat snapshot, combined with the table below, helps choose the next step:
| Symptom | Likely cause | Where to go next |
|---|---|---|
us/sy high, wa low, r large |
Not enough CPU | Process Monitoring — sort by %CPU |
wa high, b large |
Disk I/O saturated | The iostat section below |
free low, si/so nonzero |
RAM running short, swap active | Process Memory — free -h and OOM checks |
| Everything looks normal, but the service still doesn't work | The problem isn't a resource — it's configuration or code | systemd troubleshooting |
iostat: Which Disk Is at Fault
vmstat only gives the overall I/O picture — it doesn't say which device is the problem. For that, iostat, from the sysstat package, is used:
sudo is needed here because the new package is installed into system directories — the same installation process covered in apt and Repositories.
The important columns:
%util— the percentage of time the device was busy. A value near90–100%means the disk is nearly saturated, and new requests are queuing up;await— the average time a request waits, in milliseconds. For a modern SSD/NVMe drive, anawaitabove a few milliseconds is already suspicious, and tens of milliseconds indicates a serious problem.
In the output above, %util is 96% and await is 38ms — confirming exactly what the high wa in vmstat suggested: the nvme0n1 device is saturated.
Disk Space: A Separate, but Often Confused, Problem
Disk I/O (speed) and disk space (capacity) are two independent problems. A disk can be very fast but completely full, or the reverse. A quick check:
Full analysis — inode exhaustion, "the disk is full but du shows little usage," and other tricky cases — is already covered in depth in Disk and File System Basics; at the triage stage, a quick "full or not" answer from df -h is enough.
Practical Scenario: "The Site Is Responding Slowly"
Monitoring reports that web server responses have gotten slower. Every command below is read-only.
Step 1. Get the overall picture.
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
3 5 0 2100400 402100 3800200 0 0 210 8400 380 610 12 8 15 65 0
wa is 65, b is 5. The CPU itself (us+sy = 20) isn't particularly busy, but a lot of processes are waiting on disk responses.
Step 2. Identify which device is bottlenecked.
%util is nearly 100%, await is 62ms — the disk is saturated.
Step 3. Find which process is doing this writing.
A D in the STAT column means uninterruptible sleep — the process is specifically waiting on a disk I/O response. The full explanation of ps state codes is in Process Monitoring.
Conclusion: the slowdown isn't CPU or RAM — it's heavy disk writing generated by the postgres process. The next step is finding out why this process is writing so much (a large indexing operation, or a poorly written query, for example), using the application's own log source and the techniques covered in Log Analysis.
Common Mistakes
Checking Only top and Skipping Disk I/O
top can show a high %wa value, but it doesn't say which device or which process is causing it. In that situation, iostat identifies the device and the D state in ps finds waiting processes; to attribute I/O to a specific process directly, sudo iotop -o (interactive, shows only processes actually doing I/O) or pidstat -d 2 (from the same sysstat package, script-friendly) are the purpose-built tools.
Confusing %util with CPU Percentage
%util in iostat is the percentage of time the disk device was busy, not the processor. 100% CPU and 100% disk %util are completely different problems that call for different fixes.
Treating Disk Space and Disk Speed as the Same Problem
df -h might report "80% used," but that has nothing to do with I/O slowness. They are independent measurements — one is capacity, the other is throughput.
Exercises
- Run
vmstat 2 5on your own system, write down the values in ther,b, andwacolumns, and justify whether they look normal or problematic. - Install
iostatwithsudo apt install sysstatand interpret the%utilandawaitcolumns fromiostat -x 2 3for your own disk. - On a test VM, generate artificial disk load with
dd if=/dev/zero of=/tmp/testfile bs=1M count=2000(disposable VM only, inside/tmp), watchwachange withvmstat 1 5while it runs, then remove the test file:rm /tmp/testfile. - Pick three scenarios from the decision table above and write out, from memory, the sequence of checks you would run for each.
Verification criterion: for exercise 3, you should be able to point to the specific row in vmstat output where wa rises in response to the dd command, and explain why us/sy stay comparatively low during the same window.
References
- man7.org:
vmstat(8): https://man7.org/linux/man-pages/man8/vmstat.8.html - man7.org:
iostat(1): https://man7.org/linux/man-pages/man1/iostat.1.html - Sysstat Documentation: https://github.com/sysstat/sysstat
- man7.org:
ps(1)— process state codes: https://man7.org/linux/man-pages/man1/ps.1.html