Engineering Notes
Home/DevOps & Cloud/Linux/Troubleshooting a Linux Server
DevOps & Cloud · Linux

Troubleshooting a Linux Server

'The server is slow.' Work it like an engineer, not with random commands: define the problem, run the first-60-seconds checklist, apply the USE method to every resource, and only then dig into a process. Practice on real outputs.

☁️ DevOps & Cloud● Intermediate⏱ 5 min read▶ 1 interactive🛠️ 2 exercises🎤 5 interview Q&As

🎯 What you'll learn

  • A systematic method: define, USE, application, hypothesis
  • The first-60-seconds command checklist
  • Reading load, CPU, memory, disk and network signals
  • Inspecting a process with strace, lsof, perf, and common failure patterns

1A Method, Not Random Commands

When a server is "slow" or "broken", work systematically:

  1. Define the problem: what's slow/failing, since when, for whom, what changed (deploys, config, traffic, certificates expiring)?
  2. Check the big four resources with the USE method — for each resource, look at Utilization, Saturation and Errors: CPU, memory, disk I/O, network (plus file descriptors, connections, threads).
  3. Look at the application (logs, error rates, latency, dependencies).
  4. Form a hypothesis, test it, change one thing at a time, and write down what you did (the timeline feeds the post-mortem — devops-cloud/observability/).

2The First 60 Seconds

bash
uptime                      # load averages 1/5/15 min — trend up or down?
dmesg -T | tail -20         # kernel: OOM kills, disk errors, network drops
vmstat 1 5                  # r (run queue), b (blocked), si/so (swap), us/sy/wa/st CPU
mpstat -P ALL 1 3           # per-CPU: one core pegged = single-threaded bottleneck
pidstat 1 3                 # per-process CPU
iostat -xz 1 3              # per-disk: %util, await (latency), r/s w/s, aqu-sz
free -m                     # memory: look at "available", not "free"
sar -n DEV 1 3              # network throughput per interface
sar -n TCP,ETCP 1 3         # connection rate, retransmits
top / htop                  # who is consuming it

(This is Brendan Gregg's well-known checklist; sysstat provides mpstat/pidstat/iostat/sar.)

3Reading the Signals

Load average

Number of tasks running or waiting for CPU plus those in uninterruptible I/O wait (D). Compare with CPU count (nproc): load 16 on 16 cores may be fine; load 16 on 2 cores with low CPU usage points at I/O.

CPU

  • High us (user): application work — profile it (perf top, language profilers, py-spy, node --prof).
  • High sy (system): syscalls, context switches, networking — perf, strace -c -p PID.
  • High wa (iowait): CPUs idle waiting for disk.
  • High st (steal): the hypervisor gives your VM less CPU — noisy neighbours or exhausted burst credits (AWS T instances).

Memory

  • Linux uses free memory for page cache; "available" is what matters.
  • Swapping (si/so > 0 continuously) → severe slowdowns.
  • OOM killer messages in dmesg/journalctl -k; containers: OOMKilled, exit code 137.
  • Leaks: RSS of one process grows steadily (ps -o rss, pmap -x PID, app heap dumps).

Disk

  • df -h / df -i — full disk or inodes (02-filesystem_and_permissions/).
  • iostat -x: %util near 100% and high await → saturated; cloud volumes have IOPS/throughput limits and burst credits (EBS gp2!).
  • iotop / pidstat -d — who's doing the I/O.

Network

  • Retransmits, drops (ip -s link, nstat), connection states (ss -s, CLOSE-WAIT leaks), DNS latency (03-networking_tools/).
  • Limits: conntrack table full (dmesg: nf_conntrack: table full), ephemeral port exhaustion, accept queue overflows.

4Inspecting a Specific Process

bash
systemctl status app ; journalctl -u app --since "30 min ago"
ls /proc/PID/fd | wc -l ; cat /proc/PID/limits      # fd usage vs limit
strace -f -tt -p PID -e trace=network,file          # what syscalls is it stuck on?
strace -c -p PID                                     # syscall time summary (Ctrl-C)
lsof -p PID                                          # open files and sockets
cat /proc/PID/status | grep -E 'State|Threads|VmRSS'
gdb -p PID / py-spy dump --pid PID / jstack PID      # thread stacks
perf top -p PID                                      # hottest functions

strace adds heavy overhead — use briefly in production; eBPF tools (bcc/bpftrace: execsnoop, opensnoop, biolatency, tcpretrans) are low-overhead alternatives.

5Common Failure Patterns

SymptomLikely causesConfirm with
high load, low CPUdisk I/O wait, NFS hangvmstat b/wa, iostat -x, ps D state
app killed randomlyOOM killerdmesg -T | grep -i oom
"No space left on device"disk full, inodes full, deleted-open filesdf -h, df -i, lsof +L1
"Too many open files"fd limit / fd leak/proc/PID/limits, ls /proc/PID/fd | wc -l
slow only sometimesGC pauses, CPU steal, burst credits, cron jobsst in vmstat, app GC logs, list-timers
connections fail under loadaccept queue, conntrack, ports, pool limitsss -lnt Recv-Q, dmesg, ss -s
everything slow after deployregression, config change, cache colddeploy timeline, compare metrics, roll back
Under the HoodWhere the Numbers Come From▾

Nearly every tool reads kernel counters from /proc and /sys: uptime and top read /proc/loadavg (an exponentially damped moving average of runnable + uninterruptible tasks, updated every 5 seconds); vmstat/mpstat read cumulative CPU jiffies from /proc/stat and compute deltas per interval; free parses /proc/meminfo (where MemAvailable is the kernel's estimate of memory available without swapping); iostat reads /proc/diskstats (time spent doing I/O → %util, total wait time / completed I/Os → await); ss queries sockets via netlink; ps walks /proc/[pid]/stat. That's why tools that sample deltas need an interval (the first line of vmstat is the average since boot — ignore it), why %util is misleading for SSDs/NVMe that serve many requests in parallel, and why container metrics differ from host metrics (cgroup files like memory.current and cpu.stat give the per-container view).

A troubleshooting flow: define the problem and recent changes, run the first-60-seconds checks, apply the USE method to CPU, memory, disk and network with the tools that reveal utilization, saturation and errors, then drill into the specific process with logs, strace, lsof and profilers, change one thing and record the timeline
A troubleshooting flow: define the problem and recent changes, run the first-60-seconds checks, apply the USE method to CPU, memory, disk and network with the tools that reveal utilization, saturation and errors, then drill into the specific process with logs, strace, lsof and profilers, change one thing and record the timeline

⚠️ Common Pitfalls

  1. Restarting before collecting evidence — the problem disappears and returns.
  2. Reading free as "out of memory" because of page cache.
  3. Treating load average as CPU usage.
  4. Ignoring dmesg (OOM, disk errors, conntrack).
  5. Changing several things at once.
  6. Forgetting cloud limits — burst credits, IOPS caps, instance network limits.

📋 Quick Reference

text
60 s: uptime · dmesg -T | tail · vmstat 1 · mpstat -P ALL 1 · pidstat 1 · iostat -xz 1 · free -m · sar -n DEV,TCP,ETCP 1 · top
USE: utilization / saturation / errors for CPU, memory, disk, network, fds
process: journalctl -u · /proc/PID/{limits,fd,status} · strace -c/-p · lsof -p · perf top · py-spy/jstack
patterns: load≠CPU · OOM 137 · df -i · lsof +L1 · CLOSE-WAIT · st steal · burst credits

🧠 Key takeaways

  • Method first: what changed? → first 60 seconds → USE (utilization, saturation, errors) per resource → the process.
  • Load counts running and I/O-blocked tasks; high load with idle CPUs means I/O.
  • Read available memory (not free), watch swap, dmesg for OOM, steal for VM contention.
  • Collect evidence before restarting; change one thing at a time; know cloud limits (burst credits, IOPS).

🎤 Interview Q&A

Questions interviewers ask about this topic. Answer out loud first, then open a card to compare.

Q1A server is slow. What do you check first?core▾

USE method: CPU (uptime, top, steal time), memory (free -m, swapping in vmstat 1), disk (iostat -xz 1, df -h), network (sar -n DEV 1, errors, retransmits). Then logs (journalctl, dmesg) and the application's own metrics.

Follow-ups interviewers ask
  • What's Brendan Gregg's 60-second checklist? uptime, dmesg, vmstat, mpstat, pidstat, iostat, free, sar -n DEV/TCP, top.
Q2How do you tell if the system is memory-starved?core▾

Low available memory in free, swap in/out activity (si/so in vmstat), OOM killer messages in dmesg, and high major page faults.

Follow-ups interviewers ask
  • Is low 'free' memory bad? Not necessarily; Linux uses spare memory for page cache. Look at 'available'.
Q3How do you investigate high I/O wait?core▾

iostat -xz 1 for device utilization and latency (await), iotop or pidstat -d to find the process, and check for swapping, logging floods, or database checkpoints.

Follow-ups interviewers ask
  • What does high %util on SSD mean? Not always saturation; SSDs handle parallel I/O, so check latency.
Q4A process keeps dying. How do you find out why?senior▾

Check journalctl -u service, exit codes (137 = SIGKILL/OOM, 139 = segfault), dmesg for OOM kills, core dumps, resource limits (ulimit -a, file descriptors), and application logs around the time.

Follow-ups interviewers ask
  • Too many open files? Raise LimitNOFILE and check for descriptor leaks.
Q5How do you debug a hung process?core▾

strace -p <pid> to see system calls it's blocked on, lsof -p for files/sockets, /proc/<pid>/stack or gdb/language-specific tools (jstack, dotnet-dump, py-spy) for thread dumps.

Follow-ups interviewers ask
  • What's state D in ps? Uninterruptible sleep, usually waiting on I/O.

🛠️ Practice exercises

Each exercise is a file in this topic folder. Code exercises are self-checking: run them and make the checks pass.

✅ Check yourself

Answer the questions — feedback is instant.

1. Load average 16 on 2 CPUs with low CPU usage suggests…
Load includes uninterruptible sleep.
2. Which free column indicates usable memory?
Page cache is reclaimable.
3. An app dies every few hours with signal 9 and no logs. First check?
OOM kills leave kernel messages.
4. High %steal in mpstat means…
Change instance type/host.