Skip to content

Nastroje a diagnostika

Martin Skalicky edited this page Aug 7, 2026 · 1 revision

Nástroje a diagnostika systému

Server je pomalý. Devět lidí z deseti pustí top, podívá se na první řádek a řekne buď „procesor je vytížený", nebo „procesor není vytížený". Tím diagnostika skončila.

Jenže top odpovídá na jednu ze čtyř otázek, které je potřeba položit, a zbylé tři jsou v praxi častější příčinou. Když se procesor nudí a stroj přesto stojí, čeká se na disk, došla paměť, nebo se čeká na odpověď od někoho jiného.

Tahle stránka je rozcestník a tahák. Každý nástroj tu má tři věty a odkaz na stránku, kde je vysvětlené, co ta čísla znamenají. Mechanismy tu nevysvětluju znovu - ty mají správa paměti, vstup a výstup a plánování procesů. Předpokládá to procesy, protože bez stavů R, S, D a Z je polovina výstupů nečitelná. Prostředí je Debian 13, jádro 6.12, osm jader, 16 GB RAM, NVMe disk.

Čtyři zdroje a nic jiného

Tohle je nejdůležitější věc na celé stránce: každý výkonnostní problém je nedostatek jednoho ze čtyř zdrojů - procesor, paměť, disk, síť. Diagnostika není hledání viníka. Je to vyloučení tří ze čtyř.

Postup je vždycky stejný a liší se jen nástroje: celkový obraz, určení zdroje, konkrétní proces, a nakonec co ten proces dělá. Kdo přeskočí první krok, hledá vysvětlení pro číslo, které nikdy nezměřil.

flowchart TD
    A["Stroj je pomalý"] --> B{"vmstat: je us plus sy blízko 100?"}
    B -->|ano| C["Procesor: ps --sort=-pcpu, pidstat, perf top"]
    B -->|ne| D{"Je wa vysoké nebo b trvale nenulové?"}
    D -->|ano| E["Disk: iostat -xz 1, iotop -o"]
    D -->|ne| F{"Je si nebo so nenulové, je available malé?"}
    F -->|ano| G["Paměť: free -h, smaps_rollup, dmesg kvůli OOM"]
    F -->|ne| H{"Visí proces na soketu nebo na volání?"}
    H -->|ano| I["Protistrana: ss -tulpn, strace -p"]
    H -->|ne| J["Není to zdroj: zámek nebo čekání ve vlastním kódu"]
Loading

Každá větev má níž vlastní sekci. Poslední uzel je ten nepříjemný: stroj má všechno a přesto stojí, protože si program překáží sám.

Celkový obraz: uptime a vmstat 1

Zátěž (load average) neměří procesor

„Zátěž 20 na osmi jádrech znamená přetížený procesor." Tuhle větu najdeš ve stovkách návodů a na Linuxu je nesprávná.

Linux do zátěže počítá procesy ve stavu R a zároveň ve stavu D - nepřerušitelný spánek, typicky čekání na disk nebo na síťové úložiště. Ostatní Unixy počítají jen R. Dvacet procesů zaseknutých na nedostupném NFS tedy udělá zátěž 20 při procesoru nečinném na 100 %.

Zátěž ber jako otázku „stalo se něco?", nikdy jako odpověď. Tři čísla z uptime jsou navíc tlumené průměry za 1, 5 a 15 minut, takže krátkou špičku rozpustí do bezvýznamné hodnoty.

Sloupce vmstat 1

vmstat 1 tiskne řádek za sekundu a je to nejlevnější způsob, jak během deseti sekund vyloučit tři zdroje ze čtyř. První řádek zahoď, je to průměr od startu stroje.

Sloupec Co znamená Kdy se lekni
r procesy připravené běžet trvale víc než jader
b procesy v nepřerušitelném spánku trvale nenulové
si stránky načítané ze swapu nenulové delší dobu
so stránky odkládané do swapu nenulové delší dobu
bi čtení z blokových zařízení vysoké spolu s wa
bo zápis na bloková zařízení vysoké spolu s wa
in přerušení za sekundu skok o řád proti klidu
cs přepnutí kontextu za sekundu statisíce při malém r
us čas v uživatelském režimu trvale blízko 100
sy čas v jádře nad 30
id nečinnost vysoké při stížnosti na pomalost
wa nečinnost s čekáním na I/O nad 10

Vysoké cs při malém r znamená, že si procesy předávají procesor rychleji, než na něm stihnou něco udělat - cena je na přepínání kontextu. Ve virtuálním stroji sleduj navíc st, tedy čas, který ti vzal hypervizor.

Procesy: kdo z toho žere

ps aux versus ps -ef versus vlastní formát

ps aux je BSD syntaxe, ps -ef syntaxe podle POSIXu. Stejná data, jiné sloupce. Nauč se vlastní formát a obě zapomeň.

ps -eo pid,ppid,stat,pcpu,rss,wchan,comm --sort=-pcpu | head -20

wchan řekne, ve které funkci jádra proces spí, a u stavu D je to nejcennější údaj na řádku. Pozor na pcpu: ps počítá průměr za celý život procesu, ne aktuální vytížení. Proces, který týden spal a teď žere jádro naplno, tam bude mít skoro nulu.

top a co v něm mačkat

Klávesa 1 rozpadne souhrn na jednotlivá jádra. To je jediný způsob, jak v top poznat jednovláknový program s jedním jádrem na 100 % - v souhrnu je to při osmi jádrech 12,5 % a vypadá to nevinně.

Klávesa H přepne na vlákna, M řadí podle paměti, P zpátky podle procesoru. htop umí totéž čitelněji a přes F5 ukáže strom.

pidstat 1 je vmstat po procesech a jediný z téhle skupiny dává výstup, který se dá uložit a porovnat později. pstree -p odpoví, kdo koho spustil. Priority a niceplánování procesů.

Paměť: dívej se na available

free -h vyvolá paniku pokaždé: „mám volných 1,6 GB z 16". Sloupec buff/cache ale není ztracená paměť, je to hlavně page cache a jádro ji vydá, jakmile ji někdo bude potřebovat.

Jediné číslo, které z free -h čti, je available. Je to odhad jádra, kolik se dá alokovat bez odkládání do swapu. Pochází z položky MemAvailable v /proc/meminfo (od jádra 3.14, rok 2014); předtím si to každý nástroj počítal sám a špatně.

Když paměť ubývá a nevíš komu, jdi po pořadí: /proc/PID/smaps_rollup a v něm Pss místo RSS (RSS připočte sdílené knihovny každému procesu zvlášť, takže součet přes procesy vyjde větší než celá RAM), pmap -x PID na rozpis mapování, smem na PSS napříč procesy a slabtop, když paměť nedrží procesy, ale struktury jádra. Swap, thrashing a OOM killer mají výměnné algoritmy.

Disk a vstup/výstup

iostat -xz 1 je pro disk to, co vmstat 1 pro celý stroj. -x zapne rozšířené sloupce, -z vynechá zařízení bez provozu - bez něj se utopíš v třiceti řádcích loop0loop29. Čti r_await a w_await (milisekundy na požadavek včetně fronty) a aqu-sz.

iotop -o ukáže jen procesy, které právě čtou nebo zapisují. Chce root a doinstalovat, stejně jako smem a ncdu.

df -h a df -i jsou dvě různá „plno". Na souborovém systému s milionem malých souborů dojdou i-uzly dřív než bajty, zápis začne selhávat a df -h u toho hlásí volných 40 % - viz souborový systém.

Kdo mi zaplnil disk

du -sh * | sort -h na podezřelém adresáři, ncdu /var, když se chceš proklikat. du ale nevidí to nejčastější překvapení.

lsof +L1 vypíše soubory, které někdo drží otevřené, ale už nemají odkaz v adresáři. Smažeš access.log, du ho přestane počítat a df se nezmění ani o bajt, protože nginx pořád drží deskriptor. Místo se uvolní až po systemctl reload nginx.

Síť potud, kde končí systém

Síť není téma téhle wiki, ale zjistit, který proces drží port, k diagnostice systému patří. Na to je jediný příkaz: ss -tulpn - -t TCP, -u UDP, -l naslouchající sokety, -p proces, -n čísla místo jmen služeb.

netstat už nepoužívej. Balík net-tools je prakticky bez vývoje od začátku století a netstat získává data parsováním textu z /proc/net/tcp, kdežto ss se ptá jádra přes netlink a při desetitisících spojení je řádově rychlejší. V návodech zůstává setrvačností a na čerstvém Debianu často není ani nainstalovaný. Totéž platí pro ifconfig proti ip a.

ss -s dá souhrn v pěti řádcích. Když počet spojení ve stavu timewait roste do desetitisíců, problém není ve stroji, ale v tom, jak aplikace otevírá a zavírá spojení.

Co ten proces vlastně dělá

strace a jeho cena

strace -p PID vypisuje systémová volání běžícího procesu. strace -c -p PID místo výpisu sečte statistiku a po Ctrl+C vytiskne tabulku „které volání, kolikrát, kolik času, kolik chyb" - to je devadesát procent případů, kdy strace opravdu potřebuješ. -f přidá potomky, ltrace dělá totéž pro volání knihoven.

Varování: strace program zpomalí řádově. Každé zachycené volání znamená dvě zastavení procesu přes ptrace a dvě přepnutí do sledujícího procesu a zpět. Program se statisíci volání za sekundu se zpomalí desetinásobně i víc, takže na produkci pod zátěží pouštěj jen -c a na pár sekund. Co se v tom výpisu objevuje, rozebírají systémová volání.

Když strace mlčí

Prázdný výstup není chyba nástroje. Znamená, že proces visí uvnitř jednoho volání a nic nového nezačíná.

Pak se ptej jádra přímo. cat /proc/PID/wchan vypíše funkci, ve které proces spí (ep_poll je čekání na událost, futex_wait čekání na zámek), sudo cat /proc/PID/stack ukáže celý zásobník v jádře.

Na uživatelskou stranu je gdb -p PID a v něm thread apply all bt, tedy zásobníky všech vláken naráz. Bez ladicích symbolů dostaneš jen adresy, takže si gdb i symboly doinstaluj dřív, než je budeš potřebovat. Po dobu připojení je proces zastavený.

/proc je zdroj pravdy, zbytek jsou formátovače

Žádný z nástrojů výš nemá přístup k ničemu zvláštnímu. Všechny jen čtou textové soubory z /proc a hezky je formátují - strace -c ps aux ti to ukáže během vteřiny.

Soubor Co v něm je
/proc/cpuinfo jádra, model, frekvence, příznaky instrukcí
/proc/meminfo paměťová statistika včetně MemAvailable
/proc/interrupts počty přerušení po zdrojích a po jádrech
/proc/mounts co je skutečně namontované a s jakými volbami
/proc/pressure/* tlak na procesor, paměť a vstup/výstup
/proc/PID/status stav, RSS, vlákna, přepnutí kontextu
/proc/PID/limits limity procesu tak, jak platí teď
/proc/PID/fd/ otevřené deskriptory jako symbolické odkazy
/proc/PID/smaps_rollup souhrn všech mapování, hlavně Pss

Důsledek je větší, než vypadá: v kontejneru s pěti binárkami, kde není ps ani top, odladíš skoro všechno pomocí cat. A /proc/PID/limits je jediné místo se skutečnými limity běžícího procesu - ulimit -n ve tvém shellu o cizím procesu neříká nic. Proč to vypadá jako soubory, vysvětluje VFS a montování.

Logy: co systém říká sám o sobě

journalctl -b je vše od posledního startu, journalctl -f -u nginx živý výpis jedné služby a journalctl -p err -b -1 chyby z minulého startu. K tomu poslednímu se dostaneš vždycky až po pádu, tak si ho zapamatuj teď. Když -b -1 nic nevrátí, žurnál se nedrží mezi starty - založ /var/log/journal.

dmesg -T -l err,warn je kruhová vyrovnávací paměť jádra profiltrovaná na chyby a varování. Tady najdeš OOM killer, chyby disku i odpojené USB. Přepínač -T převede časy na datum, ale po uspání stroje jsou posunuté, protože se dopočítávají z uptime. Co se děje dřív, než začne psát systemd, je na startu systému.

Co stojí za naučení navíc

perf

perf top je živý profil celého stroje po funkcích, včetně funkcí jádra. Odpoví na otázku „v čem se ten čas tráví", na kterou top odpoví jen „v tomhle procesu".

perf stat ./program dá instrukce, cykly, IPC a výpadky cache, perf record -g ./program a perf report záznam k pozdějšímu prohlížení. Chce doinstalovat a mít kernel.perf_event_paranoid dost nízko.

PSI: číslo, které je lepší než zátěž

Soubory /proc/pressure/cpu, io a memory existují od jádra 4.20 (rok 2018) a řeší přesně to, co je na zátěži špatně.

Řádek some avg10=8.52 avg60=2.37 avg300=0.67 znamená, že za posledních deset sekund byla aspoň jedna úloha 8,52 % času zablokovaná čekáním na ten zdroj. Řádek full totéž pro stav, kdy čekaly všechny naráz.

PSI měří ztracený čas, ne počet procesů, a rozlišuje zdroj. Nula v /proc/pressure/io je důkaz, že disk problém není, a to zátěž neřekne nikdy. Na některých systémech je potřeba přidat psi=1 mezi parametry jádra. Vlastní sadu těchhle souborů má každá cgroup, což je z hlediska kontejnerů to nejužitečnější, co v posledních letech přibylo.

eBPF a bpftrace

Nástroje nad eBPF běží v jádře, nezastavují sledovaný proces jako ptrace a jejich režie se počítá v procentech, ne v násobcích.

Nauč se první execsnoop. Vypíše každý spuštěný proces včetně těch, které žijí dvacet milisekund a v top je nikdy neuvidíš - a přesně ty bývají příčinou záhadné zátěže z cronu. Pak opensnoop a biolatency, který dá histogram latence disku místo průměru.

Kde tyhle nástroje přestávají platit

Kontejner vidí jinou pravdu. /proc/meminfo uvnitř kontejneru hlásí paměť hostitele, ne limit cgroup, takže free -h tam lže a nproc může hlásit osm jader při kvótě půl jádra. Skutečné hodnoty jsou v /sys/fs/cgroup/.

%util z iostat na NVMe nic neznamená. Ten sloupec říká, kolik procent času mělo zařízení aspoň jeden požadavek. U plotnového disku s jednou hlavou to byla saturace, u NVMe s desítkami paralelních front může být 100 % při zlomku skutečného výkonu.

Zálohu, kterou nikdo nezkusil obnovit, nemáš. GitLab, 31. ledna 2017: administrátor při řešení zahlcené databáze smazal datový adresář PostgreSQL na špatném stroji a pak zjistil, že žádný z pěti nastavených způsobů zálohování a replikace nefunguje. Obnovilo se to ze šest hodin staré kopie, která vznikla omylem. Všech pět nástrojů přitom hlásilo, že je všechno v pořádku.

Příznak a co za ním hledat

Příznak Kde je problém
zátěž vysoká, id blízko 100 procesy ve stavu D, čekání na disk
sy výrazně vyšší než us příliš mnoho volání, ověř strace -c
cs ve statisících, r malé příliš mnoho vláken, přepínání sežere víc než práce
si a so trvale nenulové došla paměť - výměnné algoritmy
df hlásí plno, du ne smazaný soubor drží proces, lsof +L1
df má místo, zápis selže došly i-uzly, ověř df -i
paměť procesu roste a nevrací se únik nebo neomezená cache, smaps_rollup
proces nereaguje, strace nic nepíše visí uvnitř volání, čti /proc/PID/wchan
služba spadla a v logu nic není zabil ji OOM killer, hledej v dmesg -T
jedno jádro na 100 %, ostatní nic jednovláknový program, v top klávesa 1

Tahák

# Je pomalý procesor?
uptime                                     # zátěž jen jako otázka, ne odpověď
vmstat 1 10                                # r, us, sy, wa; první řádek zahoď
ps -eo pid,stat,pcpu,rss,wchan,comm --sort=-pcpu | head
pidstat 1 5
perf top

# Je pomalá paměť?
free -h                                    # čti available, ne free
grep -E 'MemAvailable|Dirty|SwapCached' /proc/meminfo
cat /proc/1234/smaps_rollup                # Pss, ne RSS
slabtop -o                                 # když paměť drží jádro
dmesg -T | grep -i 'out of memory'

# Je pomalý disk?
iostat -xz 1                               # await a aqu-sz, ne %util
iotop -o                                   # chce root
cat /proc/pressure/io

# Co dělá tenhle proces?
cat /proc/1234/status
cat /proc/1234/wchan; ls -l /proc/1234/fd
strace -c -p 1234                          # ukončit Ctrl+C
gdb -p 1234 -batch -ex 'thread apply all bt'

# Kdo mi zaplnil disk?
df -h; df -i                               # bajty i i-uzly
du -sh /var/* | sort -h | tail
lsof +L1

# Proč to spadlo?
journalctl -p err -b -1                    # minulý start
dmesg -T -l err,warn
ss -tulpn                                  # kdo drží který port

Praktická pravidla

Měň jednu věc naráz. Když změníš tři a začne to fungovat, nevíš nic.

Změř to před a po. Bez čísla z doby, kdy to bylo špatně, nemáš důkaz, jen dojem.

Nedůvěřuj průměru za pět minut, když tě zajímá špička. Dvousekundový zásek se v něm rozpustí na desetinu procenta.

Nástroj, který ti řekne, že je všechno v pořádku, nic nedokazuje. Dokazuje jen to, že se dívá jinam, než kde je problém.

Problém, který nejde reprodukovat, jsi nevyřešil. Bez reprodukce nepoznáš opravu od náhody.

Kam dál

Clone this wiki locally