-
Notifications
You must be signed in to change notification settings - Fork 0
Nastroje a diagnostika
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.
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"]
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.
„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.
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.
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 -20wchan ř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.
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 nice má plánování procesů.
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.
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 loop0 až loop29. Č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.
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íť 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í.
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í.
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ý.
Žá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í.
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.
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.
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.
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.
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 | 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
|
# 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ý portMěň 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.
-
Procesy - stavy
R,S,DaZ, bez kterých je půlka výstupů nečitelná - Plánování procesů - proč připravený proces nemusí běžet
- Správa paměti - co je RSS, co PSS a proč je součet přes procesy nesmysl
- Výměnné algoritmy - swap, thrashing a jak vybírá OOM killer
-
Vstup a výstup - page cache a fronty, které
iostatměří -
Systémová volání - co přesně vypisuje
strace -
VFS a montování - proč
/procvypadá jako soubory a není jimi
Našel jsi chybu nebo něco chybí? Založ issue nebo pošli pull request.
Základy
- Co dělá operační systém
- Režim jádra a uživatelský režim
- Systémová volání
- Přerušení a výjimky
- Architektury jádra
Procesy
Souběh
Paměť
Soubory a zařízení
Systém v provozu
Praxe