Otázka znie takmer vždy rovnako: v noci web odpovedal dvadsať sekúnd a do rána sa všetko samo napravilo. Nie je sa už na čo pozerať — top odpovedá za aktuálnu sekundu, kým otázka sa týka tretej hodiny rannej. Nižšie je, čo čísla záťaže naozaj znamenajú, ktoré z nich treba čítať v pároch a prečo jednorazové meranie mýli častejšie, než pomáha.

Load average: tri čísla a jeden častý omyl

uptime
cat /proc/loadavg
nproc

Tie tri čísla sú priemery za jednu, päť a pätnásť minút. Neporovnávajú sa s nulou, ale s počtom jadier, ktorý uvedie nproc. Hodnota 8 na osemjadrovom stroji je plná, no zdravá záťaž: práce je presne toľko, koľko server stihne vykonať. Hodnota 2 na jednojadrovom VPS je rad dvakrát dlhší, než je kapacita, a každá požiadavka čaká, kým na ňu príde rad.

Pomer troch čísel medzi sebou udáva smer. Minútová hodnota výrazne nad pätnásťminútovou znamená, že záťaž práve teraz rastie. Naopak znamená, že vrchol už prešiel a vidíte len jeho koniec.

Teraz k omylu, pre ktorý sa tieto čísla najčastejšie chápu nesprávne. Load average v Linuxe nie je „vyťaženie procesora“. Na rozdiel od iných unixových systémov doň Linux započítava nielen procesy, ktoré bežia alebo sú pripravené bežať, ale aj tie v stave D — v neprerušiteľnom spánku. Teda čakajúce na disk alebo na sieťový súborový systém. Odtiaľ server so záťažou 12 a takmer nečinným procesorom: práca nepostupuje, všetci stoja v rade.

Procesor, alebo disk

Oddeliť tieto dva prípady je prvá vec, ktorú má zmysel urobiť:

vmstat 1 5
iostat -x 1 3

Vo výstupe vmstat sa rátajú tri stĺpce. r je počet procesov v rade na procesor, b počet procesov zablokovaných čakaním na vstup a výstup a wa podiel času, ktorý procesor strávil nečinným čakaním na disk. Trvalé wa nad 10–15 % pri skromných us a sy znamená, že server naráža na disk: pridávať jadrá nemá zmysel, tie súčasné sú aj tak voľné.

Ktoré procesy čakajú, sa dá vypísať menovite:

ps -eo state,pid,comm,wchan:30 | awk '$1 ~ /^D/'

Príklad z vlastnej praxe. Vo východiskovej konfigurácii zapisuje Suricata asi tridsať typov udalostí a nijakú rotáciu si k nim nenastaví — na prevádzkovom serveri z toho bolo 15 GB logov za dva dni. Záťaž sa pritom neprejavovala ako vyťažený procesor, ale práve ako I/O wait: systém písal bez prestania a všetko ostatné stálo v rade za ním. Liekom nie je väčší balík, ale kratší zoznam typov udalostí a nastavená rotácia.

Opačný prípad, čisto procesorový a oveľa menej zjavný. Webová stránka volala apt pod používateľom, pod ktorým beží PHP-FPM. Root drží binárnu vyrovnávaciu pamäť v /var/cache/apt/pkgcache.bin — na stroji s tuctom repozitárov je to 70 MB — a mapuje si ju do pamäte zadarmo. Bežný používateľ do toho adresára písať nesmie a pri každom volaní si ju stavia nanovo. Zmerané na jednom a tom istom stroji: 0,01 sekundy procesorového času ako root proti 4,2 sekundy ako neprivilegovaný používateľ. Ten istý príkaz, štyristonásobný rozdiel, násobený každým zobrazením stránky.

Záver z oboch prípadov je rovnaký: záťaž sa meria, neháda. Odmerať každý podozrivý príkaz zvlášť zaberie pol hodiny a zvyčajne to ukáže inam, než mierilo pôvodné podozrenie.

Pamäť: free neukazuje to, ako vyzerá

free -h

Stĺpec used sám osebe hovorí veľmi málo a stĺpec free priamo mýli: Linux dáva nevyužitú pamäť stránkovej vyrovnávacej pamäti a na prvé vyžiadanie ju aplikáciám vráti. Čítať sa má stĺpec available — koľko sa dá zabrať bez toho, aby sa išlo do swapu. Veľký buff/cache nie je problém, ale znak systému, ktorý pracuje tak, ako má.

Pri swape nerozhoduje aktuálna hodnota, ale tvar. Vystúpil a vrátil sa na nulu: bol krátky vrchol. Vystúpil raz a zostal: vrchol už bol, stránky boli vytlačené a nikto ich nevracia — server pôsobí pokojne, hoci pamäť mu v istej chvíli nestačila. Či odkladanie prebieha práve teraz, ukazujú stĺpce si a so vo vmstat; nenulové hodnoty tam sú tá podoba spomalenia, ktorú používatelia vnímajú najviac.

Ak počas nočného prepadu nejaký proces jednoducho zmizol, vysvetlenie býva tu:

journalctl -k --since yesterday | grep -i "out of memory"
dmesg -T | grep -i "killed process"

Riadok typu Out of memory: Killed process 1234 (mysqld) uzavrie vec lepšie než akýkoľvek graf: databáza „nespadla sama“, zastavilo ju jadro, pretože sa minula pamäť.

Kto to robí

ps aux --sort=-%cpu | head -10
ps aux --sort=-%mem | head -10

Jedna výhrada: %CPU v ps je priemer za celý život procesu, takže krátky výkyv sa v tom zozname stratí. Naň treba top alebo pidstat 1 5, ktoré merajú za interval.

Kedy sa záťaž stáva bezpečnostnou otázkou

Rovných 100 % procesora v noci, s procesom, ktorý má nič nehovoriace meno a pracovný adresár v /tmp alebo /dev/shm, je klasický obraz ťažiara, nie webu, ktorý narástol. Špička prichádzajúcej prevádzky spolu s rastom zápisov do logov je prebiehajúci útok na heslá. Prudko narastený objem logov býva búrkou falošných poplachov nejakého filtra.

Samostatnou kategóriou sú samotné bezpečnostné nástroje. Na jednom z našich serverov sa záťaž držala okolo troch bez jediného návštevníka a na čele ps podľa nazbieraného procesorového času nestál web ani databáza, ale CrowdSec, fail2ban, Falco a Suricata. Nie je to porucha ani dôvod ich vypínať, ale cenu ochrany je dobré poznať v číslach: na slabom VPS je citeľná.

Na čo je sledovanie

Všetko vyššie uvedené odpovedá na otázku „čo sa deje teraz“. Rannú otázku — čo bolo o tretej v noci — tieto príkazy nepokrývajú: o uplynulej noci nie sú nijaké údaje, ak ich nikto nezaznamenal. A stavať kvôli jedinému VPS Prometheus s Grafanou je sporné, pretože sledujúci stack vyjde ťažší než sledovaný server.

Stačí riadok v databáze každých päť minút a jedna stránka, ktorá z neho vykreslí posledných dvadsaťštyri hodín: load average, vyťaženie procesora a osobitne I/O wait, pamäť a swap, čítanie a zápis disku, zaplnenie oddielu, i-uzly, súborové deskriptory, spojenia. Na jednej časovej osi sa dvojice čítajú voľným okom: vysoké wa pri pokojnom procesore, swap, ktorý sa nikdy nevrátil na nulu, deskriptory blížiace sa k limitu — nastupujúca chyba too many open files je vidieť hodiny predtým, než nastane. Ako to vyzerá poskladané dokopy, ukazuje ukážková stránka nižšie.