Jak myśleć o „spowolnieniach” na Linuxie – fundamenty
Opóźnienie vs przepustowość – dwa różne „typy wolności”
Większość osób wrzuca do jednego worka każde „zamulenie”: długo otwierająca się przeglądarka, lagi w terminalu SSH, powolne kopiowanie plików. Tymczasem system może być „wolny” na dwa różne sposoby: mieć wysokie opóźnienie (lag, freeze, przywieszki) albo niską przepustowość (ruch idzie, ale „żółwim tempem”). Zanim rozpocznie się analiza CPU, RAM i I/O, potrzebne jest rozróżnienie tych dwóch przypadków.
Opóźnienie (latency) to czas reakcji na pojedyncze zdarzenie: kliknięcie, komendę, zapytanie SQL. Gdy opóźnienie rośnie, użytkownik czuje, że „nic się nie dzieje”, okno jest „zamrożone”, SSH ma laga po naciśnięciu klawisza. Często odpowiada za to blokada I/O, przepełniony bufor, kolejki na dysku lub wąskie gardło jednego wątku CPU.
Przepustowość (throughput) to ilość pracy wykonywanej w jednostce czasu: liczba obsłużonych żądań HTTP, szybkość kopiowania plików, liczba zadań w kolejce. Tu „wolno” oznacza, że całościowo wykonuje się mało pracy, chociaż pojedyncza operacja wcale nie musi być dramatycznie opóźniona. Przykład: serwer www, który stabilnie, ale zbyt wolno obsługuje rosnący ruch.
Przy diagnostyce spowolnień na Linuxie pomagają dwa pytania: czy pojedyncza akcja reaguje z opóźnieniem, czy po prostu throughput jest zbyt mały? Odpowiedź kieruje dalej: w stronę CPU-bound / I/O-bound / blokad synchronizacji albo w stronę przeciążonej infrastruktury.
Trzy główne źródła spowolnień: CPU, RAM i I/O
W 80–90% przypadków winowajcą odczuwalnych spowolnień jest jeden z trzech obszarów: CPU, pamięć RAM lub I/O dyskowe. Sieć oczywiście też potrafi namieszać, ale jej analiza to osobny temat. Kluczem jest nauczyć się szybko rozpoznać, która „nogi” systemu brakuje mocy.
Problemy CPU objawiają się zwykle wysokim wykorzystaniem procesora, ale nie zawsze. Można mieć też niskie zużycie CPU i „wiszące” procesy, jeśli czekają na blokujące I/O. Typowe symptomy CPU-bound to: wentylator w laptopie wyje, jeden proces ma 100% CPU, interfejs GUI jest „poszarpany”, ale dysk nie mieli ciągle.
Problemy RAM wychodzą na wierzch, gdy system zaczyna intensywnie używać swapu lub zabija procesy OOM-killerem. Objawiają się ciężkimi przywieszkami, szarpaniem myszki, „teleportowaniem” kursora, sekundowymi pauzami przy przełączaniu okien. Z zewnątrz wygląda to jak „zamrożenie” całego systemu, choć CPU nie musi być wtedy bardzo wysoko.
Problemy I/O dyskowego to klasyczne „mielenie” dysku: dioda świeci się ciągle, odczyty i zapisy stoją w kolejkach, komendy typu ls w katalogu dużej aplikacji wiszą, terminal reaguje z dużym lagiem. Może to być skutek braku miejsca na dysku, uszkodzonego nośnika, złej konfiguracji RAID, kiepskich ustawień bazy danych.
Jednorazowy ścinek vs stały problem wydajności
Nie każde szarpnięcie systemu wymaga pełnej sekcji diagnostycznej. Jednorazowy „ścinek” (np. 1–2 sekundy laga podczas startu ciężkiej aplikacji) jest naturalny, o ile nie powtarza się regularnie i nie uniemożliwia pracy. Zwykle jest to kwestia krótkiego skoku obciążenia CPU lub I/O.
Stały problem wydajności to sytuacja, gdy opóźnienia lub niska przepustowość utrzymują się przez dłuższy czas albo wracają według jasnego wzorca: co godzinę, co noc, za każdym razem przy tym samym zadaniu. To już powód, by włączyć top, iostat, vmstat, sprawdzić logi i zaplanować konkretną diagnozę.
Dobrym nawykiem jest krótkie notowanie momentów spowolnień (czas, co akurat było wykonywane, ilu użytkowników). Pomaga to później skorelować dane z logami systemowymi i metrykami monitoringu, zamiast strzelać na oślep.
Dlaczego intuicja bywa myląca przy diagnozie spowolnień
Naturalny odruch: „system chodzi wolno, to pewnie brakuje mu RAMu albo procesor za słaby”. Często to błędna diagnoza. 90% CPU nie zawsze jest problemem – gdy kompilujesz jądro, renderujesz wideo czy kompresujesz archiwa, chcesz zużyć CPU maksymalnie. To raczej powód do radości, że sprzęt jest wykorzystywany.
Podobnie z RAM-em: „prawie pełna pamięć” pokazana przez free to w typowym systemie Linux efekt agresywnego cache’owania dysku, a nie brak pamięci. Jeżeli buff/cache jest wysoki, a swap prawie nietknięty, system zwykle działa zdrowo.
Nawet wysokie odczyty load average nie muszą oznaczać tragedii, jeśli serwer ma wiele rdzeni i większość zadań to krótkie, aktywnie przetwarzane wątki. Dopiero po spojrzeniu na strukturę obciążenia (CPU, I/O, kolejki) widać, czy load jest „zdrowy”, czy jest wynikiem korka I/O lub procesu zombie w pętli.
Jak użytkownik odczuwa różne typy wąskich gardeł
Po kilku takich doświadczeniach, łatwo zacząć rozpoznawać typ wąskiego gardła po objawach:
- CPU-bound: mysz działa płynnie, ale aplikacje reagują wolno, wentylator głośny; top pokazuje 100% CPU dla kilku procesów.
- RAM-bound / swapowanie: całość „pływa”, nawet ruch myszki się tnie, przełączanie kart w przeglądarce jest bolesne; si/so w vmstat stale rośnie.
- I/O-bound: dysk mieli, proste komendy (np. ls, cd) potrafią wisieć, load average rośnie, a CPU wcale nie musi być zapchany.
- Sieć: lokalnie wszystko działa płynnie, ale zdalne zasoby (SSH, strony) są powolne, pingi rosną, iftop/nload wskazują saturację łącza.
Im szybciej nauczysz się wiązać te symptomy z konkretnymi typami problemów, tym sprawniej będzie przebiegać każda kolejna analiza systemu Linux.
Szybka „diagnostyka z fotela” – co sprawdzić w pierwszych 60 sekundach
Czy problem dotyczy wszystkiego, czy tylko wybranych aplikacji
Na początek warto zadać sobie jedno krótkie pytanie: czy laguje absolutnie wszystko, czy tylko jedna aplikacja/usługa? Jeśli cały system jest „przycięty”, podejrzenie pada na zasoby ogólnosystemowe: CPU, RAM, I/O, jądro, sterowniki. Jeżeli tylko jedna aplikacja, to łańcuch diagnostyki będzie krótszy i bardziej skoncentrowany na jej procesach.
Dobry test: otworzyć terminal (lokalnie lub wirtualną konsolę Ctrl+Alt+F2) i spróbować:
- wpisać kilka komend (ls, cd, echo)
- sprawdzić, czy przełączanie między TTY działa płynnie
- uruchomić prosty edytor tekstu w terminalu (np. nano)
Jeśli te działania są szybkie, a np. przeglądarka czy IDE wisi, problem leży prawdopodobnie w konkretnej aplikacji (lub w tym, z czego ona korzysta – baza, NFS, serwer HTTP). Gdy nawet konsola reaguje z dużym opóźnieniem, trzeba patrzeć szerzej.
Pierwszy rzut oka: uptime, load average, CPU, pamięć
W ciągu pierwszej minuty można zbudować podstawowy obraz sytuacji kilkoma prostymi komendami:
uptime
top -b -n 1 | head -n 15
free -h
df -h
uptime pokaże od ilu godzin/dni system działa oraz aktualny load average. Już tutaj widać, czy np. po restarcie problem wraca od razu, czy pojawia się dopiero po dłuższym czasie.
top da szybki widok: obciążenie CPU (w tym us, sy, id, wa, st), listę procesów, ilość pamięci i swapu. Przefiltrowanie nagłówka (head -n 15) pomaga skupić się pierwszym kroku na metrykach ogólnych zamiast szczegółach procesów.
free -h jasno pokaże, ile RAM jest fizycznie zajęte przez procesy, ile stanowi cache, a ile jest wolne. df -h natomiast zdradzi, czy na którymś z montowanych systemów plików nie kończy się miejsce – to częsty, a bagatelizowany powód lawinowych problemów (zwłaszcza na /var, /tmp, partycji z bazą danych).
Rozpoznanie typu spowolnienia po kilku symptomach
Na podstawie powyższych informacji można już wstępnie określić kierunek:
- Jeżeli CPU ~100%, us wysoko, wa nisko, load average wysoki – stawiaj na CPU-bound.
- Jeśli wa (iowait) > 20–30%, load rośnie, dysk mieli – wąskie gardło to prawdopodobnie I/O dyskowe.
- Gdy swap użyty w dużej części, si/so w vmstat nie spadają, a free pokazuje bardzo mało pamięci „available” – system jest RAM-bound.
- Jeśli load average wysoki, a CPU prawie wolne, to sygnał, że wiele procesów czeka w kolejkach (zwykle I/O lub locki).
Po takim wstępnym „skanie” od razu wiadomo, czy w następnej kolejności bardziej opłaca się wchodzić w iostat, vmstat, czy w narzędzia do profilowania CPU i procesów.
Kiedy szukać problemu w sieci, a kiedy w lokalnym systemie
Część „spowolnień” nie ma nic wspólnego z lokalnym CPU, RAM czy I/O. Zanim pogrążysz się w logach jądra, wykonaj prosty test: czy lokalne operacje są szybkie? Przykładowo:
- uruchomienie lokalnego edytora tekstu
- kopiowanie pliku między lokalnymi katalogami
- proste komendy systemowe w terminalu
Jeśli lokalne zadania są responsywne, a jedynie połączenia zdalne lagują (SSH, www, bazy danych w sieci), wina zwykle leży po stronie łącza, routera, firewalla, przeciążonego serwera docelowego albo problemu z DNS. Wtedy warto włączyć ping, mtr, traceroute, a zasoby lokalne zostawić na później.
Własny rytuał diagnostyczny – szybki schemat działania
Największą przewagę daje wypracowanie stałego schematu pierwszej analizy. Przykładowa krótka checklista „z fotela” może wyglądać tak:
- 1. Otwórz lokalny terminal / TTY i sprawdź, czy reakcja jest płynna.
- 2. Sprawdź
uptimei zwróć uwagę na load average. - 3. Uruchom
toplubhtop, rzuć okiem na CPU, iowait, pamięć, topowe procesy. - 4. Sprawdź pamięć:
free -h, poziom swapa. - 5. Zweryfikuj miejsca na dyskach:
df -h, szczególnie na /, /var, /tmp, partycji baz.
Taki rytuał oszczędza czas i nerwy – po kilkunastu sytuacjach stanie się odruchem, który w minutę zawęża pole poszukiwań.

Kluczowe metryki systemowe – jak je czytać, żeby cokolwiek zrozumieć
Load average – co mówi o kondycji systemu
Load average to jedna z najbardziej mylonych metryk. W skrócie opisuje średnią liczbę zadań w kolejce do CPU plus zadań aktualnie wykonywanych w danym przedziale czasowym (1, 5, 15 minut). Nie jest to „procent wykorzystania procesora”, tylko miara „jak długie są kolejki do wykonania pracy”.
Najistotniejszy jest związek load average z liczbą rdzeni. Jeśli system ma 4 rdzenie, to load ~4 oznacza ogólnie wykorzystanie na poziomie 100% (przybliżając). Load ~1 na tym samym serwerze jest bardzo spokojny. Dopiero load znacząco większy niż liczba rdzeni sugeruje przeładowanie kolejki.
Warto też porównywać 1-min, 5-min i 15-min load:
Jak interpretować 1/5/15-min load w praktyce
Trzy liczby load average to podpowiedź, czy problem jest epizodyczny, czy narasta latami (albo przynajmniej godzinami):
- 1 min > 5 min > 15 min – coś niedawno „wystrzeliło”. Może backup, cron, odpalone testy. Krótkotrwałe piki są normalne.
- 1 min ≈ 5 min > 15 min – obciążenie rośnie, ale jeszcze niedawno było spokojniej. Dobry moment, żeby złapać winowajcę, zanim rozkręci się na dobre.
- 1 min ≈ 5 min ≈ 15 min i wszystkie wysokie – chroniczne przeciążenie. Tu już nie wystarczy „zabić jeden proces”, zwykle potrzebna jest zmiana konfiguracji, limitów albo skali.
- 1 min < 5 min < 15 min – system się uspokaja po wcześniejszym „stormie”. Jeżeli teraz działa ok, zainteresuj się raczej tym, co było zaplanowane 10–30 minut temu (crony, batch, kopie).
Dobry nawyk: skojarzyć dziwny load z kalendarzem zadań. Jeżeli co dzień o 2:00 w nocy load skacze pięciokrotnie, a o 2:30 wraca do normy, to nie „losowy problem”, tylko przewidywalny wzorzec – idealny kandydat do optymalizacji.
CPU: user, system, iowait, steal – co naprawdę oznaczają
Patrzenie na jedno „%CPU” niewiele daje, bo ważna jest struktura. W top (lub mpstat) pojawiają się m.in.:
- us (user) – czas wykonywania kodu użytkownika. Dużo us = aplikacje ciężko pracują.
- sy (system) – czas w jądrze. Skoki sy to zwykle syscall-e, obsługa I/O, sieci.
- id (idle) – bezczynność CPU. Wysokie id przy wysokim load to sygnał, że procesy na coś czekają (np. na dysk).
- wa (iowait) – CPU się nudzi, bo czeka na dane z I/O. Często znak, że dysk jest zbyt wolny lub zasypany zadaniami.
- st (steal) – ważne na VM-kach: czas, kiedy hypervisor „zabiera” CPU tej maszynie na rzecz innych. Wysoki st = problem po stronie hosta/virtualizacji, nie wewnątrz gościa.
Prosty wzorzec rozpoznawania:
- us wysoki, sy umiarkowany, wa niski – CPU robi swoje, klasyczny scenariusz „kod intensywny obliczeniowo”. Szukasz procesów, które liczą.
- sy wysoki, us niski – jądro pracuje ciężej niż aplikacje. Sprawdź intensywne I/O, sieć, firewall, system plików, eBPF, antywirusa.
- wa wysoki, id nie jest zerowe – CPU czeka na I/O, nie jest tak naprawdę przeciążone. Tutaj fokus przenosi się na dyski, RAID, storage sieciowy.
- st wysoki – VM „dusi się”, bo host jest przeładowany lub ma złe limity. Upewnij się, że dostajesz tyle vCPU, na ile liczysz.
Rozbicie CPU na te składowe od razu mówi, czy zaglądać w kod aplikacji, czy w storage, czy raczej dzwonić do zespołu od wirtualizacji.
Pamięć: used, free, buff/cache, available – jak to czytać bez paniki
Wyjście free -h potrafi przestraszyć, gdy ktoś widzi „free: 200 MB na 16 GB RAM”. W Linuksie to normalne, bo nieużywana pamięć to zmarnowana pamięć. Kluczowe kolumny:
- used – wszystko, co nie jest aktualnie oznaczone jako wolne, w tym cache.
- free – faktycznie „puste” strony RAM, których system jeszcze do niczego nie przypisał.
- buff/cache – pamięć na bufory bloków i cache stron z dysku. Może zostać szybko oddana procesom.
- available – najlepszy skrót: ile RAM można przydzielić bez agresywnego swapowania. To na tę liczbę patrz w pierwszej kolejności.
Jeśli available jest wysokie, a swapa praktycznie brak – system czuje się dobrze, nawet jeśli used+buff/cache niemal równa się total. Gdy available spada bardzo nisko, a swap zaczyna szybko rosnąć, zaczyna się realne „dławienie”.
Swap: kiedy jest zdrowy, a kiedy zabija responsywność
Sam fakt użycia swapa nie jest zły. Niewielka ilość (kilka–kilkanaście procent) używana statycznie to często „chłodnia” dla rzadko używanych stron pamięci. Problem zaczyna się, gdy:
- swap usage stale rośnie, aż wypełnia się prawie cały
- liczniki si/so w vmstat tykają bez przerwy – ciągły ruch do/z swapa
- system reaguje z opóźnieniem sekundowym przy prostych akcjach (pisanie w terminalu, przesuwanie okna)
To znak, że RAM jest realnie za mało w stosunku do zestawu działających usług lub jedna aplikacja ma wyciek pamięci. W takiej sytuacji tymczasowe zabicie jednego ciężkiego procesu potrafi doraźnie uratować dzień, ale i tak trzeba zrozumieć źródło – logi, monitoring, profilowanie pamięci.
I/O: co oznaczają wysokie kolejki i iowait
I/O to nie tylko „dysk jest wolny”. Czasem problemem jest konfiguracja RAID, zbyt agresywne logowanie albo współdzielony storage sieciowy. Podstawowe narzędzia:
iostat -xz 1– szczegółowe metryki I/O per urządzenie, aktualizowane co sekundę.vmstat 1– skrócony widok CPU, pamięci i I/O.
W iostat istotne są:
- %util – ile czasu w próbce urządzenie było zajęte. Blisko 100% oznacza, że dysk non-stop coś robi.
- r/s, w/s – liczba odczytów/zapisów na sekundę. Wysokie wartości nie zawsze złe, jeśli latency jest niskie.
- await – średni czas obsługi operacji (kolejka + wykonanie). Dziesiątki–setki ms przy małych I/O bolą.
- avgqu-sz – przeciętna długość kolejki. Stale wysokie wartości oznaczają korek do dysku.
Scenariusz typowy z praktyki: prosty serwer plików z jednym HDD, na którym ktoś odpala skan antywirusowy + backup w tym samym czasie. iostat pokazuje 100% util, ogromne kolejki, a zwykłe ls w katalogu użytkownika wisi sekundami. Sam CPU jest prawie wolny – i to jest kluczowa wskazówka, że to nie „za słaby procesor”.
Narzędzia pierwszego kontaktu: top, htop, free, ps, df
top – szybki radar problemów
top jest wszędzie i uruchamia się natychmiast, dlatego świetnie nadaje się jako pierwsze narzędzie. Kilka klawiszy, które znacząco zwiększają jego użyteczność:
- M – sortowanie procesów po zużyciu pamięci.
- P – sortowanie po CPU (domyślnie).
- 1 – przełączanie widoku na poszczególne rdzenie CPU.
- Shift + i – przełączanie pokazywania wątków vs procesów (przydatne przy JVM, Nginx itp.).
- k – zabicie procesu (używać świadomie).
Kiedy top pokazuje jednego „potwora” z 300–400% CPU (na maszynie z wieloma rdzeniami), droga jest prosta: sprawdzasz ten proces, jego argumenty i powiązane logi. Jeśli obciążenie rozkłada się po równo po dziesiątkach procesów – np. wiele instancji serwera aplikacyjnego – wtedy kluczowe jest spojrzenie w głąb konkretnej usługi, nie tylko w jeden PID.
htop – wygodniejszy kuzyn z kolorami
htop robi to samo, tylko wygodniej. Daje myszkę, filtrowanie, drzewo procesów i przyjazne kolory. Przy szukaniu winowajców pomaga szczególnie:
- podgląd drzewa procesów (F5) – łatwo zobaczyć, co jest dzieckiem czego
- szybkie filtrowanie po nazwie (F3) – wpisujesz „java”, „postgres”, „chrome” i widzisz tylko to
- kolorowe paski CPU, RAM, swap – szybka ocena, co jest wysycone
Przy analizie spowolnień interaktywnych (desktop, środowisko graficzne) htop daje czytelniejszy obraz niż surowy top, zwłaszcza gdy chodzi o wiele procesów tej samej aplikacji.
free – szybkie spojrzenie na stan pamięci
free -h to podstawowe narzędzie do odpowiedzi na pytanie: „czy naprawdę brakuje RAM-u?”. Typowy sposób patrzenia:
free -h
total used free shared buff/cache available
Mem: 15Gi 12Gi 200Mi 500Mi 2.5Gi 2.0Gi
Swap: 4Gi 500Mi 3.5Gi
Tutaj used wygląda groźnie, ale available = 2 GiB, swap użyty umiarkowanie. System ma jeszcze przestrzeń oddechową. Problem zaczyna się, gdy dostępna pamięć zjeżdża w okolice setek MB, a swap dynamicznie rośnie. W takich sytuacjach htop posortowany po pamięci (kolumna RES) szybko pokaże największych „pożeraczy”.
ps – chirurgiczne namierzenie procesu
Kiedy już wiesz, że problem powoduje konkretny PID albo użytkownik, ps pozwala zbudować dokładny obraz:
ps aux --sort=-%cpu | head
ps aux --sort=-%mem | head
ps -p <PID> -o pid,ppid,user,%cpu,%mem,cmd
W pierwszej komendzie widzisz „TOP 10” po CPU, w drugiej po pamięci. Trzecia jest świetna, gdy z top wyciągnąłeś PID, ale chcesz znać pełną linię komendy – z argumentami, ścieżką itd. Często już tu wychodzą na jaw oczywistości: nie ten plik konfiguracyjny, nie ten profil, kompletnie zbędny tryb debugowania.
df – kiedy „brak miejsca” zabija wszystko po kolei
Brak przestrzeni na dysku to klasyczny, podstępny winowajca. Najprostszy test:
df -h
df -ih
Pierwsze wyjście pokaże procenty zajętości, drugie liczbę inode’ów. Dwa najczęstsze scenariusze:
- pełny /var – logi, pliki tymczasowe, spoolery maili. Aplikacje zaczynają dziwnie się zachowywać, bazy nie mogą zapisać danych, system logów staje.
- zajęte 100% inode’ów – miliony malutkich plików (np. cache aplikacji, poczta, uploady). „df -h” może pokazywać jeszcze wolne GB, ale df -ih krzyczy 100% i żaden nowy plik nie powstanie.
Jeśli system „dziwnie laguje”, a w logach mnożą się błędy typu „No space left on device”, sprzątanie (logrotate, kasowanie starych plików, rotacja backupów) potrafi dać natychmiastowego kopa w responsywność.

Analiza obciążenia CPU – od prostego „kto zjada CPU” do profilu procesu
Identyfikacja głodnych procesów
Na początek wystarczy typowa sekwencja:
top -o %CPU
# lub
ps aux --sort=-%cpu | head
Jeśli widzisz jeden lub kilka procesów z wysokim %CPU, zadaj sobie trzy krótkie pytania:
- czy ten proces powinien teraz tak pracować (np. kompilacja, backup, migracja)?
- czy pracuje długo i ciągle, czy to chwilowy pik?
- czy skalował się razem z obciążeniem (duży ruch = dużo CPU), czy „odjechał” bez powodu?
Jeżeli odpowiedzi są zdroworozsądkowe („tak, to zaplanowana migracja”), analiza jest prosta. Jeśli nie – trzeba pogłębić temat.
Rozbicie po wątkach i rdzeniach
Niektóre procesy są wielowątkowe i samo %CPU jednego PIDA niewiele mówi. Wtedy przydają się:
top -H -p <PID> # wątki procesu
ps -L -p <PID> -o pid,tid,%cpu,cmd
Można zobaczyć, czy cały proces „pali” jeden wątek na 100%, czy obciążenie rozkłada się po kilku. Jeśli tylko jeden TID „wariuje”, profilowanie ogranicza się do tego wątku – a to potrafi zaoszczędzić mnóstwo czasu.
Profilowanie CPU lekkimi narzędziami
Gdy wiadomo, który proces podnosi %CPU, kolejnym krokiem jest sprawdzenie, co on tak naprawdę robi. Na początek wystarczą lekkie narzędzia, które nie zabiją produkcji:
pidstat -p <PID> 1– użycie CPU przez dany proces w czasie, z podziałem na user/system.strace -p <PID>– podgląd wywołań systemowych (I/O, waity, sygnały). Używać krótkimi seriami.perf toplubperf record– lekkie próbkowanie stosu wywołań jądra i user-space.
Dobry trik: jeśli proces ma 100% CPU, a strace nie pokazuje prawie żadnych wywołań systemowych, to duża część czasu spędzana jest w czystym kodzie user-space (algorytmy, pętle, parsowanie, GC). Jeśli natomiast strace sypie tysiącami read(), write(), fsync() lub futex(), problem częściej leży w I/O lub blokadach.
Diagnoza: CPU-bound, I/O-bound czy coś między
Patrząc na proces z wysokim CPU, warto szybko ustalić, czy to faktycznie „młóci procesor”, czy tylko czeka na dysk/sieć, a licznik CPU jest efektem ubocznym. Pomaga prosty zestaw:
pidstat -p <PID> 1
iostat -xz 1
vmstat 1
Jeśli w pidstat rośnie głównie kolumna %usr, dysk jest względnie wolny, a iowait małe – to klasyczny CPU-bound. Gdy natomiast %sys jest wysokie, a w tym samym czasie iostat pokazuje duże kolejki i 100% util na dysku, proces jest raczej I/O-bound, ale zużywa CPU na obsługę przerwań i wywołań systemowych.
Przy takiej diagnozie szybciej decydujesz, czy szukać optymalizacji w kodzie (algorytmy, konfiguracja JVM, parametry serwera), czy raczej w storage (cache, zmiana typu dysków, tuning kolejek I/O).
Głębsze profilowanie: perf, flamegraphy i „gorące ścieżki”
Gdy problem jest powtarzalny i boli realnie, opłaca się zrobić głębszy profil. Na nowoczesnych kernelach perf daje bardzo dużo przy małym koszcie:
# próbkuj konkretny proces przez 30 sekund
perf record -F 99 -p <PID> -g -- sleep 30
# potem przeglądaj raport interaktywnie
perf report
W perf report widać funkcje, w których proces spędza najwięcej czasu, oraz ścieżki wywołań. Jeśli większość próbek skupia się w jednej funkcji (np. parser JSON, sortowanie, pętla szyfrująca), masz konkretny cel do rozmowy z developerami lub do tuningu konfiguracji.
Dla bardziej wizualnego podejścia można na podstawie danych z perf script wygenerować flamegraph:
perf script > out.perf
# dalej narzędzie FlameGraph (stackcollapse-perf.pl, flamegraph.pl)
Flamegraph podpowiada, gdzie „płonie” CPU – jeden szeroki segment to miejsce, gdzie opłaca się inwestować czas w optymalizację. Nawet jednorazowa taka analiza potrafi oszczędzić tygodnie zgadywania.
Kiedy wysoki CPU jest… dobry
Czasem proces z prawie 100% CPU jest zjawiskiem pożądanym: transkodowanie wideo, kompresja, intensywna analiza danych. Klucz to kontekst:
- czy są SLA opóźnień (np. API, aplikacja webowa), które w tym czasie cierpią,
- czy zadanie można ograniczyć poziomem równoległości (
--threads,-j, konfiguracja workerów), - czy obciążenie występuje w zaplanowanych oknach (noc, niski ruch), czy uderza w „prime time”.
Jeśli CPU jest wykorzystany, ale load average zbliża się do liczby rdzeni, I/O trzyma się sensownie, a userzy nie skarżą się na lagi – nie ma czego „naprawiać”. Zamiast walczyć z każdym skokiem CPU, lepiej dodać sensowny monitoring i zrozumieć, które skoki są naturalne.
RAM, cache i swap – jak rozpoznać, że system dusi się przez pamięć
Różnica między „użytym RAM-em” a „brakiem pamięci”
Na Linuxie „pusty RAM” to stracona szansa na cache. Dlatego klasyczne 90% użycia pamięci nic jeszcze nie mówi. Objawem bólu są dopiero efekty:
- rosnący, aktywnie używany swap (si/so w
vmstat), - długie czasy reakcji przy prostych operacjach,
- OOM-killer w logach (procesy zabijane przez kernel).
Dobre pierwsze spojrzenie dają trzy rzeczy naraz: free -h, vmstat 1 oraz htop z sortowaniem po pamięci. Zestawiając je, widać, czy pamięć zapycha jeden demon, czy „wszyscy po trochu”.
Jak czytać kolumny RSS, VIRT i CACHE
Przy analizie procesów łatwo się pogubić w kolumnach pamięci. Podstawowe znaczenia:
- VIRT – cały adres przestrzeni wirtualnej przydzielony procesowi (łącznie z mapowanymi plikami, bibliotekami). Często wielokrotnie większy niż realnie używana pamięć.
- RES / RSS – resident set size, faktycznie trzymane w RAM strony procesu.
- SHR – pamięć współdzielona z innymi procesami (biblioteki, segmenty współdzielone).
Wysoki VIRT sam w sobie nie jest alarmem (np. Java, przeglądarki). Groźnie robi się dopiero, gdy RES wielu procesów zbliża się do fizycznego RAM-u, a dostępna pamięć (available z free) spada nisko. Wtedy każdy dodatkowy proces lub spike ruchu może uruchomić spiralę swapowania.
vmstat i /proc/meminfo – bardziej szczegółowe spojrzenie
Gdy free nie wystarcza, można zajrzeć głębiej:
vmstat 1
cat /proc/meminfo | egrep 'MemFree|MemAvailable|Buffers|Cached|Slab|Anon'
W vmstat sekcja pamięci (swpd, free, buff, cache) oraz kolumny si/so pokazują, jak dynamicznie używany jest swap. W /proc/meminfo można podejrzeć:
- Active(file) / Inactive(file) – cache plików; ich wzrost przy obciążeniu I/O jest normalny.
- Active(anon) / Inactive(anon) – anonimowe strony (sterty procesów); duży „anon” to zwykle aplikacje trzymające dane w pamięci.
- Slab – pamięć na struktury jądra; rzadko winowajca, ale przy bugach lub złej konfiguracji bywa.
Takie szczegóły pomagają odróżnić „system, który ma dużo cache, ale jest stabilny” od sytuacji, gdzie aplikacje stopniowo zjadają każdy wolny megabajt.
Wyciek pamięci vs normalny wzrost
Proces, który „zjada” pamięć, nie zawsze ma wyciek. Przykłady normalnych scenariuszy:
- baza danych zwiększa rozmiar cache buforów,
- serwer HTTP utrzymuje pulę workerów w RAM,
- JVM rozgrzewa heap do zadanej wartości maksymalnej.
Niepokojący obraz wygląda tak:
- RES jednego procesu rośnie liniowo wraz z czasem działania, bez „ząbków” w dół,
- po spadku ruchu pamięć nie jest zwalniana,
- po restarcie proces znów startuje od małej wartości i powoli dobija do tego samego sufitu.
Najprościej to zauważyć, logując co jakiś czas ps -p <PID> -o pid,rss,cmd (np. w cronie) albo używając metryk z monitoringu (Prometheus, Zabbix). Chodzi o wykres, nie pojedynczy zrzut – dopiero krzywa pokazuje, czy proces się „rozpędza”.
Jak swap wpływa na odczuwalne lagi
Gdy system zaczyna mocno swapować, użytkownik czuje to jako przycinki myszki, „zamrażanie” terminala, wolne otwieranie prostych aplikacji. Z technicznego punktu widzenia dzieje się kilka rzeczy jednocześnie:
- kernel przerzuca rzadko używane strony RAM do swapa,
- aktywne strony (np. terminal, przeglądarka) walczą o miejsce w RAM,
- każde przełączenie kontekstu może wymagać ściągnięcia czegoś z dysku.
Nawet przy szybkim SSD różnica między dostępem do RAM a swapem to przepaść. Jeśli vmstat pokazuje ciągły ruch w si/so, a iostat 100% util na dysku systemowym, czas na działanie: ograniczenie liczby usług, restart „spuchniętej” aplikacji, a w dłuższej perspektywie – dołożenie RAM-u lub optymalizację konfiguracji.
Ustawienia swappiness i overcommit – kiedy je ruszać
Dwa parametry jądra mocno wpływają na zachowanie pamięci:
vm.swappiness– jak chętnie kernel sięga po swap (0–100).vm.overcommit_memoryivm.overcommit_ratio– strategia przydzielania pamięci ponad fizyczny RAM.
Podgląd bieżącej konfiguracji:
sysctl vm.swappiness
sysctl vm.overcommit_memory vm.overcommit_ratio
Na serwerach aplikacyjnych często schodzi się z swappiness z wartości domyślnej (np. 60) w okolice 10–20, żeby swap nie wchodził do gry za wcześnie. Z kolei przy dużych bazach danych typowe jest ustawienie overcommit_memory=2 i sensownego overcommit_ratio, żeby kernel był bardziej zachowawczy przy deklaracjach dużych bloków pamięci.
Zmiany tych parametrów dobrze najpierw przećwiczyć na testowym środowisku i monitorować efekty. Ślepe przestawienie wszystkiego na „0” bywa gorsze niż lekko agresywny swap.
Rozsądne limity pamięci dla usług
Jeśli na jednym hoście mieszka wiele usług, przydaje się twarde ograniczenie pamięci dla każdej z nich. Narzędzia zależą od sposobu uruchamiania:
- systemd –
MemoryMax=,MemoryHigh=w unitach. - cgroups / docker – flagi
-m,--memory-reservation, limity w YAML-u. - JVM –
-Xms,-Xmxdopasowane do realnego RAM-u, a nie „bo tak z dokumentacji”.
Takie limity nie tylko chronią przed jednym „uciekającym” procesem, ale też ułatwiają diagnozę: gdy usługa regularnie dobija do swojego limitu i jest zabijana, wiadomo dokładnie, gdzie leży problem, zamiast zgadywać po całym systemie.
Typowe scenariusze „system dławi się RAM-em”
Kilka wzorców, które często wracają:
- desktop z przeglądarką + IDE – RAM dociągnięty do granic, swap aktywny, wszystko „pływa”. Pomaga ograniczenie liczby kart, wyłączenie ciężkich wtyczek, czasem po prostu dołożenie pamięci.
- serwer z jedną dużą bazą i kilkoma mniejszymi usługami – baza rozpycha cache, system zaczyna usuwać cache plików innych usług, one z kolei zwiększają I/O. Ratunkiem bywa wydzielenie bazy na osobny host lub twarde limity pamięci.
- mikrousługi w kontenerach – każda „mała” usługa ma zbyt duży heap lub buffory; w efekcie na nodzie brakuje przestrzeni. Rozwiązanie to inwentaryzacja: ile realnie RAM-u potrzebuje każda aplikacja przy typowym ruchu.
Im szybciej rozpoznasz taki wzorzec, tym mniej czasu spędzisz na nerwowym zabijaniu pojedynczych procesów.
Narzędzia do długofalowej obserwacji pamięci
Jednorazowy zrzut jest przydatny, ale prawdziwy obraz dają dopiero wykresy w czasie. Do monitorowania pamięci warto podłączyć:
- Prometheus + Grafana (metryki node_exporter, cAdvisor),
- Zabbix, Netdata lub inne lekkie rozwiązanie z gotowymi dashboardami,
- metyki aplikacyjne (np. JMX dla JVM, pg_stat_bgwriter dla Postgresa).
Na takim wykresie szybko widać, czy problem pamięci to incydent (np. jednorazowa migracja) czy trend (każdego dnia użycie RAM rośnie o kilka procent). Mając te dane, decyzje o optymalizacji albo rozbudowie sprzętu są oparte na faktach, a nie przeczuciu.
Najczęściej zadawane pytania (FAQ)
Jak szybko sprawdzić, dlaczego Linux nagle zwolnił?
W pierwszej minucie zrób prosty „przegląd z fotela”. Uruchom terminal (albo przełącz się na TTY: Ctrl+Alt+F2) i sprawdź, czy proste komendy typu ls, cd, echo działają płynnie. Jeśli terminal też laguje, problem jest systemowy (CPU, RAM, I/O, sterowniki); jeśli tylko konkretna aplikacja się wlecze, skup się na niej.
Następnie wykonaj: uptime, top -b -n 1 | head -n 15, free -h, df -h. To pokaże aktualny load average, obciążenie CPU, zużycie RAM i swapu oraz ewentualny brak miejsca na dysku. Już po tych czterech komendach zwykle widać, w którą stronę iść dalej.
Jak rozpoznać, czy problem jest z CPU, RAM czy dyskiem (I/O)?
Po objawach można to wyczuć naprawdę szybko. CPU-bound: mysz i system działają w miarę płynnie, ale aplikacje przeliczają długo, wentylator wyje, a w top widzisz procesy zbliżające się do 100% CPU. RAM-bound: wszystko „płynie”, nawet ruch myszki się tnie, przełączanie okien boli, a w vmstat lub top widać intensywne użycie swapu.
Przy I/O-bound dysk „mieli” bez przerwy, dioda świeci ciągle, a proste komendy typu ls potrafią wisieć kilka sekund; CPU wcale nie musi być wtedy wysoko. W top zwróć uwagę na wa (iowait) – jeśli rośnie powyżej ~20–30%, masz wąskie gardło na dysku.
Czym się różni opóźnienie (latency) od przepustowości (throughput) w Linuxie?
Opóźnienie to czas odpowiedzi na pojedynczą akcję: kliknięcie, komendę w terminalu, zapytanie HTTP. Gdy rośnie latency, użytkownik czuje „zawieszki”, laga w SSH, zamrożone okna. Typowe przyczyny to blokujące I/O, kolejki na dysku, czekanie na jeden gorący wątek CPU.
Przepustowość to ilość pracy wykonanej w jednostce czasu, np. liczba obsłużonych żądań HTTP na sekundę czy prędkość kopiowania plików. Może być niska, nawet jeśli pojedyncze żądanie nie ma gigantycznego opóźnienia. To ważne rozróżnienie: inne narzędzia i decyzje podejmujesz, gdy boli Cię lag, a inne, gdy system „robi za mało roboty na godzinę”.
Czy wysokie użycie CPU albo „prawie pełny RAM” zawsze oznaczają problem?
Nie. Wysokie zużycie CPU jest często pożądane: kompilacja, render, kompresja – te zadania mają prawo używać procesora na 100%. Problem zaczyna się, gdy przy pełnym CPU interfejs reaguje źle, a użytkownik nie może normalnie pracować. Wtedy trzeba sprawdzić, co dokładnie ten procesor „zjada” i czy da się to rozbić na więcej wątków, ograniczyć lub przenieść w inne okno czasowe.
Podobnie z RAM: w Linuxie „prawie pełna” pamięć to zwykle cache dyskowy, który przyspiesza system. Kluczowe jest to, co dzieje się ze swapem. Jeśli free -h pokazuje wysoki buff/cache, a swap jest prawie pusty, wszystko jest zdrowe. Jeśli swap rośnie, system zaczyna szarpać, a vmstat pokazuje stałe si/so – wtedy rzeczywiście brakuje pamięci.
Jak odróżnić jednorazowy ścinek od stałego problemu wydajności?
Jednorazowy ścinek to np. 1–2 sekundy laga przy starcie ciężkiej aplikacji czy krótkim piku I/O. Jeśli nie powtarza się regularnie i nie utrudnia pracy, można to przyjąć jako normalne zachowanie przy obciążeniu. Typowy przykład: uruchomienie IDE lub przeglądarki z setką zakładek po restarcie.
Stały problem wydajności to sytuacja, gdy opóźnienia lub niska przepustowość utrzymują się przez dłuższy czas albo wracają według wzorca: co godzinę, o konkretnej porze dnia, zawsze przy tym samym zadaniu. Wtedy zacznij notować: czas, co akurat robisz, ilu jest użytkowników. To pozwala później łatwo powiązać objawy z logami i metrykami monitoringu i wreszcie trafić w sedno zamiast strzelać na ślepo.
Jakie komendy są najlepsze na start diagnozy spowolnień w Linuxie?
Na początek wystarczy kilka podstawowych narzędzi:
uptime– pokazuje, jak długo działa system i aktualny load average.top -b -n 1 | head -n 15– szybki obraz CPU (us, sy, id, wa, st), pamięci i listy „najgorszych” procesów.free -h– realne zużycie RAM, cache i swapu.df -h– stan miejsca na dyskach; przepełnione/varlub/tmppotrafi sparaliżować system.
Te cztery komendy dają bazę do decyzji, co sprawdzać dalej: szczegółowe statystyki I/O (iostat), pamięci (vmstat), konkretnych procesów (ps, pidstat) albo np. sieci (iftop, nload). Wystarczy kilka minut praktyki, żeby z tego „pakietu startowego” wyciągać bardzo konkretne wnioski.
Jak rozpoznać, że problem leży w sieci, a nie w CPU/RAM/I/O?
Jeśli lokalnie wszystko działa płynnie – terminal, edytor tekstu, komendy na plikach – a spowolnienia dotyczą tylko operacji zdalnych (SSH, strony WWW, bazy przez sieć), podejrzenie pada na łącze. Dobry test: sprawdź ping do serwera, wykonaj traceroute i podejrzyj ruch iftop lub nload.
Gdy rosną czasy odpowiedzi, pojawia się utrata pakietów albo interfejs sieciowy jest „przyklejony” do maksimum, winowajcą jest sieć, nie CPU czy RAM. To uwalnia Cię od bezsensownego grzebania w konfiguracji systemu i pozwala od razu szukać problemu w routerze, dostawcy lub konfiguracji usług sieciowych.






