LinuxLXXX · Common Failure ScenariosCommon failures
Failure: OOM kills, CPU saturation and disk latency
What you'll learn
- Confirm an OOM kill from the kernel log and read which process was chosen
- Separate runnable-queue saturation from iowait and from steal time
- Use pressure stall information to name the contended resource
- Distinguish a saturated device from a slow device
Prerequisites
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-11
“The server is slow” arrives with no layer attached. Memory, CPU and storage each produce it, they produce it differently, and the wrong diagnosis leads to the wrong purchase order.
Pressure first, then the specific tool
Pressure stall information gives you the contended resource in one file, before you pick a tool:
$ grep . /proc/pressure/*/proc/pressure/cpu:some avg10=2.11 avg60=1.84 avg300=1.20 total=98213441
/proc/pressure/io:some avg10=61.44 avg60=58.02 avg300=41.77 total=8821334219
/proc/pressure/memory:some avg10=0.00 avg60=0.00 avg300=0.00 total=118442Illustrative output
some is the share of time at least one task was stalled on
that resource; full (in the same files) is the share where
every task was. In the capture above, 61% of the last ten
seconds had something blocked on I/O and nothing was blocked
on memory. That is a storage investigation, and load average
would not have told you so.
Memory: the OOM kill is written down
An out-of-memory kill is never ambiguous, because the kernel records it:
$ journalctl -k -b | grep -iE 'out of memory|oom-kill|Killed process' | tailkernel: postgres invoked oom-killer: gfp_mask=0x140dca(GFP_HIGHUSER_MOVABLE|__GFP_COMP|__GFP_ZERO), order=0, oom_score_adj=0
kernel: Out of memory: Killed process 2841 (java) total-vm:9812344kB, anon-rss:7623112kB, file-rss:0kB, shmem-rss:0kB, UID:998 pgtables:16192kB oom_score_adj:0Illustrative output
Read both lines. The process that invoked the OOM killer is
usually the one that asked for memory it could not get. The
process that was killed is the one with the highest
oom_score - typically the largest resident process, which is
often innocent. A database killed because a batch job allocated
20 GB is the classic shape.
Three variants that trip people up:
- Cgroup OOM. With systemd
MemoryMax=or a container limit, only that cgroup is out of memory. The host has free memory andfree -mlooks fine. Look formemory cgroup out of memoryin the same log, and checksystemctl show UNIT -p MemoryMax -p MemoryPeak. - No OOM, but heavy reclaim.
/proc/pressure/memoryis high,vmstatshowssi/soswapping, everything is slow and nothing was killed. This is worse for latency than a clean kill. - A silent death. A process that vanished with no OOM line
and no crash was probably killed by something else. Check
journalctl -u UNITfor the systemdResult=, andcoredumpctl list.
CPU: saturation is a queue, not a percentage
100% CPU utilisation is not a failure. A queue is:
$ vmstat 1 5procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
14 0 0 411236 91244 3120448 0 0 8 22 4113 9022 92 6 1 1 0
15 1 0 409884 91244 3120448 0 0 0 16 4088 8974 93 6 0 1 0Illustrative output
r is the number of runnable tasks. Sustained r far above
the CPU count means tasks are waiting for a core - real
saturation, and latency is already degraded. The same three
columns settle the layer:
- High
us(user): the application is doing work. Profile it. - High
sy(system): kernel time. Syscall storm, interrupt load, or a pathological workload. - High
wa(iowait): the CPU is idle waiting for storage. This is a storage problem reported by a CPU tool. - Non-zero
st(steal): the hypervisor is not giving you the CPU you asked for. Nothing on the guest can fix it.
Steal time is worth its own habit. On a virtual machine it is the difference between “our application got slower” and “our neighbour got busier”, and only one of those has a fix inside your account.
Disk: saturated is not the same as slow
$ iostat -xz 1 3Device r/s w/s rkB/s wkB/s r_await w_await aqu-sz %util
nvme0n1 12.0 980.0 96.0 125440.0 0.42 18.66 18.30 99.4Illustrative output
%utilnear 100 on an SSD or an array means “busy”, not “full”. These devices serve many requests in parallel, so%utilsaturates long before the device does. It is a misleading number on modern storage.awaitis the latency the application actually experiences. Compare it to what the device should do: sub-millisecond for NVMe, a few milliseconds for SSD, ~10 ms for spinning disk.aqu-sz(average queue size) separates the two cases. Highawaitwith a deep queue is saturation - you are asking for more than the device can deliver. Highawaitwith a shallow queue is a slow device - a failing disk, a degraded array rebuilding, a saturated SAN path, or a throttled cloud volume that has spent its burst credits.
That distinction decides the action. Saturation is fixed by reducing or spreading the load. A slow device is fixed by fixing the device.
- Read /proc/pressure to name the resource.
- For memory, confirm or exclude an OOM kill in the kernel log, and check the cgroup limit before the host total.
- For CPU, read the run queue and split us/sy/wa/st before profiling anything.
- For storage, read await and queue depth together; treat %util as a hint only.
- Attribute the load to a cgroup or process before changing capacity - otherwise you buy hardware for a leak.
Knowledge check
Knowledge check · 5 questions
Q1. The OOM killer log shows postgres invoking the killer and java being killed. Which statement is best supported?
Q2. `vmstat 1` shows 4 CPUs, `r` sustained at 15, `us` 92, `wa` 1, `st` 0. What is the failure?
Q3. `iostat -xz` shows w_await of 40 ms with an average queue size of 0.6 on an NVMe device. What does that indicate?
Q4. A container can be OOM-killed while the host still has gigabytes of free memory.
Q5. Which observations point at storage rather than CPU, even though they appear in CPU tools? Select all that apply.
Passing score: 75%. Answers are checked in this browser.