Performance triage and troubleshooting
A repeatable method for a slow server: load, memory, CPU, disk and I/O, then syscall-level evidence.
A method before a tool
- For each resource — CPU, memory, disk, network — ask three questions: how utilised is it, how saturated (is work queuing), and is it producing errors?
- Work from the outside in: whole machine first, then the process, then the threads, then the syscalls.
- Measure once, change one thing, measure again. Tuning two variables at once teaches you nothing.
- Write down what changed before the slowness started: a deployment, a config edit, a traffic shift, a cron job.
- Prefer short samples of the real workload over a single instantaneous reading.
uptime # load average over 1, 5 and 15 minutes
free -h # memory, buffers/cache and swap
df -h / # space; df -i for inodes
dmesg -T | tail -30 # kernel messages: OOM kills, I/O errors, link flaps
systemctl --failed💡
Load average counts processes in the runnable and uninterruptible states, so a high load with idle CPU usually means processes waiting on disk or the network, not a CPU problem. Compare load to the number of cores: load 8 is fine on 16 cores and alarming on 2.
The main tools and what each answers
| Tool | Question it answers |
|---|---|
top / htop | Which process is hot right now, and in which state |
vmstat 1 | Is CPU busy in user, system, or waiting on I/O |
iostat -xz 1 | Per-disk utilisation, queue depth and latency |
iotop -oPa | Which process is generating the disk I/O |
pidstat -u -r -d 1 | CPU, memory and I/O per process over time |
sar -n DEV 1 | Network throughput and errors per interface |
ss -s / ss -tn state time-wait | Socket counts and connection states |
nproc / lscpu | How much CPU you actually have to compare against |
sudo apt install sysstat # provides iostat, pidstat and sar
vmstat 1 5
iostat -xz 1 3
sudo iotop -oPa
pidstat -u -r -d 1 5
# read the columns that matter
# vmstat: r = runnable, b = blocked, si/so = swap in/out,
# us/sy/id = cpu split, wa = waiting on I/O
# iostat: %util near 100 and high await = the device is the bottleneck- Non-zero
si/soin vmstat means the box is swapping and memory is the real problem. - High
wawith idle CPU points at storage or a network filesystem, not at your code. - Sustained
%utilnear 100 with a growing queue is a saturated disk; a short spike is normal.
Going deeper
# what is this process doing, right now?
sudo strace -f -tt -T -p 1234 2>&1 | tail -40
sudo strace -c -p 1234 # syscall summary with time and errors
ltrace -p 1234 # library calls, when you need them
sudo lsof -p 1234 | wc -l # open files and sockets
sudo ls -l /proc/1234/fd | wc -l
cat /proc/1234/status | grep -E 'Threads|VmRSS|FDSize'
cat /proc/1234/limits | grep 'open files'
ulimit -n # soft limit for this shell
ulimit -Hn # hard limit
# 'Too many open files' means the limit, not the disk# raise the limit for a service, not for the whole machine
# /etc/systemd/system/app.service.d/limits.conf
[Service]
LimitNOFILE=65535
sudo systemctl daemon-reload && sudo systemctl restart app
# a container needs it too - it inherits the daemon's limit
docker run --ulimit nofile=65535:65535 app:1.0straceslows the target dramatically. Use-fto follow threads,-Tfor time in each call, and stop as soon as you have your answer.- An
EAGAIN,EMFILEorECONNRESETin a syscall trace is often the entire diagnosis. - When the app is CPU-bound with no obvious hot function, sample it with
perf topor a profiler instead of staring attop.
FAQ
How do I tell a memory leak from a cache that is simply using RAM?
Look at
available in free -h rather than free. Linux uses spare RAM as cache and releases it on demand; a leak shows as falling available, rising swap activity, and a specific process's RSS growing without bound in pidstat -r.The CPU is pegged at 100% and I cannot find which process?
Check for many short-lived processes with
pidstat -u 1 or atop, look at top -H to see individual threads inside a single process, and confirm nothing is running inside a container or namespace you are not looking at.Related
Disks, filesystems and mounts Networking: addresses, DNS and firewalls
Last refreshed 2026-09-18.