Infra, Illustrated.
LINUX FOUNDATION · TROUBLESHOOTING CONSOLE

Observability & Troubleshooting

Put on your detective hat and diagnose unreachable services, saturated resources, and kernel faults by gathering empirical system evidence.

← Back to Linux MapREFERENCE HOST · devbox-01DEEP DIVE · FOUNDATIONALPublished Sep 15, 2026 · Reviewed Sep 18, 2026
CHAPTER 08 / 08 · 7 VISUAL LESSONS

What this chapter builds

This chapter combines the previous seven. Start from the caller symptom, preserve evidence, localize the first broken boundary, and change one variable at a time.

By the end, you can

  • Turn a vague outage report into competing hypotheses
  • Choose probes that discriminate between layers
  • Recognize CPU, memory, storage, FD, and network saturation
  • Verify recovery from both system and caller perspectives

Objects to keep straight

pressure countersqueuesresource limitsjournal recordssocket and task state

Applied task: Diagnose eight “site down” fixtures without restarting the service as the opening move.

SCENARIO · devbox-01 / nginxUnreachable app
OBJECT Client Error SignalSTATE ready to inspectOWNER operator evidence loop
01 / TROUBLESHOOTING · SYSTEM MODEL

Deconstruct service outages into verifiable failure signatures.

When a user reports "the site is down," how do you isolate network, host, and application root causes?

DEVBOX-01 · SYSTEM MODELREADY TO INSPECT
Connection refused means the host is alive but the port is closed (TCP RST). Connection timed out means a firewall or routing rule dropped the packet silently.

A client error code is the first clue in an incident investigation. A "Connection refused" error means the target IP received the packet, but no socket was listening on that port, causing the kernel to respond immediately with a TCP RST packet. A "Connection timed out" error means packets vanished into the void—typically dropped by an ingress firewall or security group. Form a hypothesis based on the error signature and verify each layer with specific commands before modifying system state.

Model scope. Reverse proxies (nginx, AWS ALB) return HTTP 502 (Bad Gateway) when the upstream application crashes, and HTTP 504 (Gateway Timeout) when the application hangs or exhausts its worker pool.

INSPECT · curl -Iv https://devbox-01:443 2>&1 | head -n 10
* Trying 10.0.1.17:443...
* TCP_NODELAY set
* connect to 10.0.1.17 port 443 failed: Connection refused
* Failed to connect to devbox-01 port 443: Connection refused
* Closing connection 0
curl: (7) Failed to connect to devbox-01 port 443: Connection refused
NEXT PROBE · ping -c 2 10.0.1.17
PING 10.0.1.17 (10.0.1.17) 56(84) bytes of data.
64 bytes from 10.0.1.17: icmp_seq=1 ttl=64 time=0.210 ms
64 bytes from 10.0.1.17: icmp_seq=2 ttl=64 time=0.198 ms

--- 10.0.1.17 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss
Primary source ↗
02 / TROUBLESHOOTING · EVIDENCE BOARD

The USE Method: Systematically inspect Utilization, Saturation, and Errors.

How do senior SREs triage an unfamiliar server incident without guessing or running random commands?

DEVBOX-01 · EVIDENCE BOARDREADY TO INSPECT
CPUtop / mpstat (Util)vmstat run-queue (Sat)mcelog / dmesg (Err)
MEMORYfree -m (Util)vmstat si/so swap (Sat)dmesg OOM killer (Err)
STORAGEdf -h / iostat (Util)iostat await queue (Sat)df -i / dmesg I/O (Err)
NETWORKip -s link (Util)netstat -s listen (Sat)ethtool -S drops (Err)
Apply the USE Method: for CPU, Memory, Storage, and Network, systematically verify Utilization, Saturation, and Errors.

Instead of guessing or blindly restarting daemons, apply Brendan Gregg's USE Method: for every hardware and software resource (CPU, Memory, Storage, Network), inspect Utilization (percentage of time the resource was busy), Saturation (the degree to which extra work is queued waiting for service), and Errors (explicit fault counters). Gathering empirical evidence across these four dimensions isolates the constrained bottleneck within minutes.

Model scope. High CPU utilization alone is not an incident if latency and error rates remain within acceptable SLOs; prioritize diagnosing Saturation (processes queued waiting for CPU or disk).

INSPECT · vmstat 1 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 204800  50000 1500000    0    0    12    45  500  800 15  5 78  2  0
 1  0      0 204650  50000 1500000    0    0     0     0  450  750 12  4 84  0  0
 1  0      0 204600  50000 1500000    0    0     0    20  480  790 14  5 81  0  0
NEXT PROBE · iostat -xz 1 2 2>/dev/null || sar -d 1 2 2>/dev/null || df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   18G   30G  38% /
Primary source ↗
03 / TROUBLESHOOTING · PIPELINE WALKTHROUGH

Systemd journald and /var/log provide high-fidelity chronological flight data.

How do you navigate systemd's structured binary journal to find the exact moment an outage began?

DEVBOX-01 · EXECUTION PIPELINESTAGE 01 / 04 ACTIVE
INTERACTIVE STAGE STEPPER

Stage 01: Filter strictly by unit name (-u) and time window (--since) to isolate the target service failure without drowning in unrelated system logs.

$ journalctl -u nginx.service --since "15 minutes ago" --no-pager
Sep 16 14:02:11 devbox systemd[1]: Starting A high performance web server...
Sep 16 14:02:11 devbox nginx[890]: nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
Sep 16 14:02:11 devbox systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Sep 16 14:02:11 devbox systemd[1]: nginx.service: Failed with result 'exit-code'.

Filter strictly by unit name (-u) and time window (--since) to isolate the target service failure without drowning in unrelated system logs.

Filter journald by unit (-u), priority (-p err), and time window (--since) to rapidly pinpoint service failure causes.

Modern Linux systems centralize logging in systemd-journald, which captures standard output, standard error, syslog events, and kernel messages into structured binary journal files. Querying journald with targeted flags (-u for service unit, -p for severity priority, -k for kernel events, and --since for time boundaries) allows operators to isolate failure sequences in seconds.

Model scope. If /var/log/journal does not exist, journald stores logs in /run/log/journal/ (volatile RAM), causing all historical logs to be lost on system reboot.

INSPECT · journalctl -u nginx.service -n 5 --no-pager
Sep 16 14:02:11 devbox nginx[890]: nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
Sep 16 14:02:11 devbox systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
NEXT PROBE · dmesg -T | tail -n 5
[Wed Sep 16 13:55:01 2026] Out of memory: Killed process 842 (python3) total-vm:2097152kB, anon-rss:1048576kB, file-rss:0kB
Primary source ↗
04 / TROUBLESHOOTING · COMPARISON MODEL

Resource exhaustion hits 4 distinct operational cliffs; each has unique symptoms.

Which resource limit causes cryptic application crashes when CPU and general memory appear healthy?

DEVBOX-01 · COMPARISON MODELREADY TO INSPECT
1. DATA BLOCKSdf -h (100% full)Writes fail with ENOSPC
2. INODE SLOTSdf -i (0 free)No metadata slots; ENOSPC
3. FILE DESCRIPTORSulimit -n (exhausted)EMFILE: Too many open files
4. MEMORY / OOMoom_score_adj (killed)Kernel terminates hungry PID
Always verify all four resource cliffs: df -h (blocks), df -i (inodes), ulimit -n (file descriptors), and dmesg -T | grep -i oom (memory).

Operating system failures frequently stem from hitting one of four critical resource ceilings: Data Blocks (df -h full), Inode Slots (df -i full, usually caused by millions of tiny session or cache files), File Descriptors (reaching per-process RLIMIT_NOFILE or system file-max), or Memory (where the kernel invokes the OOM killer to terminate processes and salvage the host). Each condition triggers distinct error codes in application logs.

Model scope. Per-process file descriptor limits (configured via /etc/security/limits.conf or systemd LimitNOFILE=) are typically set much lower (1024 or 65536) than the system-wide maximum.

INSPECT · df -h / && df -i /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   49G     0 100% /
Filesystem     Inodes IUsed IFree IUse% Mounted on
/dev/sda1        3.2M  3.2M     0  100% /
NEXT PROBE · cat /proc/sys/fs/file-nr
1280    0    524288
# Allocated FDs: 1280 · Free allocated: 0 · Maximum allowable FDs: 524,288
Primary source ↗
05 / TROUBLESHOOTING · PIPELINE WALKTHROUGH

Deconstructing CPU load average, memory pressure, and swap thrashing.

Why can a system have high load average with low CPU utilization, and what does "free" memory really mean on Linux?

DEVBOX-01 · EXECUTION PIPELINESTAGE 01 / 04 ACTIVE
INTERACTIVE STAGE STEPPER

Stage 01: Load average reflects threads in Runnable (R) state PLUS Uninterruptible Sleep (D, waiting for disk/NFS I/O). A load average higher than your CPU core count with low %CPU indicates an I/O bottleneck, not CPU saturation.

$ uptime
 14:20:01 up 10 days,  4:12,  2 users,  load average: 8.52, 6.10, 4.85

Load average reflects threads in Runnable (R) state PLUS Uninterruptible Sleep (D, waiting for disk/NFS I/O). A load average higher than your CPU core count with low %CPU indicates an I/O bottleneck, not CPU saturation.

Available RAM, not Free RAM, measures memory headroom. High load average with high %wa indicates a disk I/O bottleneck.

Understanding Linux performance requires looking past surface metrics. A machine with only 300 MB of "free" RAM may actually have 3.3 GB of "available" memory ready to be reclaimed from the kernel Page Cache. Similarly, a high load average combined with high "%wa" (iowait) indicates that processes are blocked waiting on slow storage disks rather than competing for CPU compute cores.

Model scope. In virtualized cloud instances (AWS EC2, GCP Compute Engine), high "%st" (steal time) in top means the underlying physical CPU is oversubscribed and other virtual machines are starving your CPU.

INSPECT · free -h
               total        used        free      shared  buff/cache   available
Mem:           7.8Gi       4.1Gi       300Mi        50Mi       3.4Gi       3.3Gi
Swap:          2.0Gi       100Mi       1.9Gi
NEXT PROBE · vmstat 1 2
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0 102400 307200  51200 3481600    0    0     0     0  500  800 10  4 86  0  0
Primary source ↗
06 / TROUBLESHOOTING · EVIDENCE BOARD

Interactive incident simulation matrix: Diagnose 8 real-world host failure modes.

Can you correctly identify whether a service failure is caused by DNS, bind scope, firewall drop, OOM, or disk exhaustion?

DEVBOX-01 · EVIDENCE BOARDREADY TO INSPECT

Service active; socket bound to 127.0.0.1:443. Remote connections cannot reach that bind address.

Different root causes leave distinct evidence fingerprints. Cross-examine systemd status, socket listeners, firewall rules, and kernel logs.

Identical surface symptoms—such as "website is down" or "API unreachable"—can stem from completely distinct root causes across the stack. A stopped service refuses connections instantly; a firewall DROP causes client connection timeouts; a DNS failure aborts before network transmission; and kernel OOM kills the worker process without warning. You must cross-examine evidence from multiple subsystems to isolate the truth.

Model scope. Use the interactive Incident Simulation selector above to load and diagnose all 8 real-world failure fixtures.

INSPECT · systemctl is-active nginx && ss -lnt 'sport = :443'
active
LISTEN 0 511 127.0.0.1:443 0.0.0.0:*
NEXT PROBE · journalctl -u nginx -n 5 --no-pager
Sep 16 10:00:00 devbox systemd[1]: Started A high performance web server.
Primary source ↗
07 / TROUBLESHOOTING · RUNBOOK STATE MACHINE

The 60-Second Linux Triage Runbook: First commands on an unfamiliar broken host.

When an emergency alert fires and you SSH into a broken server, what exact command sequence should you run?

DEVBOX-01 · RUNBOOK STATE MACHINEACTION 01 / 07 ACTIVE
RUNBOOK ACTION STEPPER

Action 01: Check Uptime & Load Average

$ uptime
 14:20:01 up 10 days,  4:12,  2 users,  load average: 0.15, 0.20, 0.18

Field Note: How long has the machine been up? Did an unexpected reboot occur? Is load average spiking above CPU core count?

Execute the 60-second triage ladder in order: uptime -> dmesg -> free -> df -> ss -> systemctl --failed -> top.

When responding to a production incident, follow a standardized diagnostic ladder before making changes or restarting daemons. The 60-second triage runbook systematically checks CPU load, kernel hardware logs, memory pressure, storage block/inode headroom, listening sockets, failed systemd units, and top processes. Gathering this baseline evidence prevents destroying diagnostic clues.

Model scope. Never blindly reboot or restart services during an incident before gathering triage evidence; restarting clears transient logs, memory states, and network sockets.

INSPECT · uptime && free -h && df -h /
 14:20:01 up 10 days,  4:12,  2 users,  load average: 0.15, 0.20, 0.18
               total        used        free      shared  buff/cache   available
Mem:           7.8Gi       4.1Gi       300Mi        50Mi       3.4Gi       3.3Gi
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   18G   30G  38% /
NEXT PROBE · systemctl --failed
0 loaded units listed.
Primary source ↗