Jak znaleźć wąskie gardła CPU, RAM i dysku w serwerze

0
32
Rate this post

Nawigacja:

Czym naprawdę jest wąskie gardło w serwerze

Definicja wąskiego gardła z perspektywy praktyka

Wąskie gardło w serwerze to konkretny komponent (CPU, RAM, dysk, sieć lub warstwa aplikacyjna), który jako pierwszy przestaje nadążać za rosnącym obciążeniem i ogranicza dalszy przyrost wydajności. Jeżeli dołożenie kolejnych wątków, użytkowników czy zadań nie zwiększa liczby obsłużonych żądań na sekundę, tylko wydłuża czas odpowiedzi – gdzieś wystąpiło wąskie gardło.

Istotne jest słowo „ogranicza”. Sam fakt wysokiego użycia CPU czy zajętej pamięci nie jest jeszcze dowodem na wąskie gardło. Kryterium jest jedno: czy obecny stan zasobu uniemożliwia spełnienie wymaganego poziomu usług (SLA) przy aktualnym lub oczekiwanym obciążeniu. Jeżeli serwer pracuje z 80–90% CPU, ale czasy odpowiedzi API są stabilne, a throughput rośnie liniowo z liczbą żądań – nie ma realnego problemu.

Wysokie użycie vs realny problem z wydajnością

Jedno z najczęstszych nieporozumień: utożsamianie „wysokiego” użycia z „problemem”. W praktyce:

  • Wysokie zużycie CPU – w serwerach obliczeniowych czy aplikacyjnych jest wręcz pożądane. „Zielony” CPU (10–20%) przy dużym ruchu oznacza często, że wąskie gardło leży gdzie indziej (np. dysk, baza danych, zewnętrzne API).
  • Duże wykorzystanie RAM – nowoczesne systemy lubią wykorzystywać pamięć na cache FS, page cache, buffery. Prawie pełny RAM przy braku swapowania może być znakiem dobrego wykorzystania zasobów.
  • Wysokie statystyki IO – duża liczba IOPS czy wysoki throughput nie jest problemem, jeśli latency jest stabilne, a kolejki nie rosną bez granic.

Problem zaczyna się wtedy, gdy rośnie czas odpowiedzi, liczba błędów, przekraczane są SLA, a kolejne przydzielane zasoby (np. nowe instancje aplikacji) nie przynoszą proporcjonalnego zysku. Wtedy warto szukać komponentu, który „pierwszy się zapcha”.

Perspektywa użytkownika a perspektywa administratora

Administrator patrzy na metryki: CPU, RAM, IO, liczbę procesów, wątki, load average. Użytkownik biznesowy patrzy na coś innego:

  • czas logowania do systemu,
  • czas generowania raportu,
  • czas odpowiedzi API z punktu widzenia aplikacji klienckiej,
  • liczbę reklamacji „działa wolno / nie działa”.

Wąskie gardło ma znaczenie tylko wtedy, gdy przekłada się na odczuwalną degradację. Dlatego diagnozę trzeba prowadzić dwutorowo:

Z jednej strony metryki techniczne: CPU, RAM, IO, sieć, metryki aplikacji. Z drugiej – metryki biznesowe: czas odpowiedzi kluczowych transakcji, throughput na API, czas przetwarzania wsadu (batch). Jeśli metryki systemowe wyglądają „źle”, ale użytkownicy tego nie odczuwają i SLA jest spełnione, być może inwestycja w nowy sprzęt przyniesie zerowy zwrot.

Wąskie gardła okresowe, sezonowe i stałe

Obciążenie serwerów rzadko bywa równomierne. Zwykle widoczny jest rytm dobowy (godziny pracy użytkowników), a w wielu systemach także rytm tygodniowy lub miesięczny (raporty, zamknięcia okresów, backupy).

Można wyróżnić:

  • Wąskie gardła stałe – serwer jest permanentnie przeciążony przy typowym ruchu. Obciążenie CPU, latency dysku czy poziom swapu są wysokie niemal cały czas.
  • Wąskie gardła okresowe – problemy pojawiają się w powtarzalnych oknach czasowych (np. nocne backupy, poranne logowania tysięcy użytkowników, okna raportowe). Poza tymi okresami serwer działa poprawnie.
  • Wąskie gardła sezonowe – szczyty ruchu w określonych dniach lub okresach (Black Friday, koniec miesiąca, kampanie marketingowe).

Diagnoza oparta na pojedynczym „snapshotcie” (np. zrzut ekranu z top lub Task Managera) jest obarczona dużym błędem. Prawdziwy obraz daje monitoring ciągły z historią, który pozwala prześledzić, kiedy dokładnie rosną opóźnienia i jakie zasoby mają wtedy anomalie.

Jak przygotować się do diagnostyki – kontekst, cele i hipotezy

Ustalenie objawów biznesowych zamiast zaczynać od CPU

Pierwszy krok to nazwanie objawów w języku biznesu, a nie w języku metryk. Kluczowe pytania:

  • Co dokładnie „działa wolno”? Logowanie, wyszukiwanie, generowanie raportów, API dla mobilki?
  • Kiedy to się dzieje? Rano, w południe, w nocy, w konkretnych dniach?
  • Jaki jest oczekiwany czas odpowiedzi, a jaki jest obecnie?
  • Czy problem jest powtarzalny, czy incydentalny?

Przykład z praktyki: zespół zgłasza, że „serwer bazy jest za słaby, wszystko mieli”. Po wstępnej rozmowie okazuje się, że:

  • problemy występują wyłącznie przy generowaniu dużych raportów ad hoc,
  • czas odpowiedzi transakcji online jest w normie,
  • raporty odpalane są ręcznie przez kilku analityków – czasem równolegle.

Taki opis sugeruje raczej złe planowanie zadań/raportów i konflikt zasobów niż ogólny „za słaby serwer”. Dopiero do tak opisanego problemu dokleja się metryki systemowe.

Formułowanie hipotez przed wejściem w metryki

Zanim zacznie się analizować wykresy, warto postawić robocze hipotezy, które będzie można potwierdzić lub obalić. Przykładowe hipotezy:

  • „W godzinach 8–10 CPU osiąga saturację i procesy stoją w kolejce do wykonania.”
  • „Przy generowaniu raportów dysk ma bardzo wysoką latencję i długie kolejki IO.”
  • „Brakuje RAM, system agresywnie swapuje, stąd skokowe zwiększenie czasu odpowiedzi.”
  • „Wąskie gardło nie leży w systemie, tylko w aplikacji – zła konfiguracja wątków, blokady w kodzie, GC itp.”

Hipotezy ukierunkowują wybór metryk: dla CPU – load average, runnable queue, profilowanie procesów; dla RAM – swap, page faults, cache; dla IO – latency, queue depth, rodzaj obciążenia. Zamiast bezładnie „patrzeć na wszystko”, fokusuje się wysiłek na kilku możliwych scenariuszach.

Znaczenie okna czasowego i obciążenia szczytowego

Diagnostyka w godzinach, kiedy nikt nie korzysta z systemu, prowadzi do fałszywego poczucia bezpieczeństwa. Jeżeli problemy pojawiają się o 9:00, a analiza jest robiona o 14:00, wnioski będą błędne.

Dlatego:

  • należy zebrać metryki z okresów, gdy użytkownicy zgłaszają problemy,
  • jeśli to możliwe – powtórzyć obciążenie (np. testy wydajnościowe) w kontrolowanym środowisku,
  • zwrócić uwagę na zadania w tle (backup, reindeksacja, batch), które mogą „nakładać się” na szczyt ruchu.

Często okazuje się, że serwer ma wystarczające zasoby na normalne obciążenie, ale kilka zadań tła odpalanych o tej samej godzinie tworzy krótkotrwałe, ale mocne wąskie gardło IO lub CPU. Bez spojrzenia na oś czasu trudno to uchwycić.

Inwentaryzacja: bez kontekstu sprzętowego diagnoza kuleje

Zanim zacznie się interpretować liczby, warto zebrać twarde dane o środowisku:

  • rodzaj serwera: fizyczny (bare-metal), VM wirtualizowana, kontener, chmura (IaaS/PaaS),
  • liczba i typ CPU (rdzenie, hyper-threading, generacja),
  • ilość RAM, typ (np. ECC),
  • rodzaj storage: lokalny SSD/HDD, RAID, SAN, NAS, EBS w chmurze itd.,
  • jakie inne systemy współdzielą ten sam storage lub hosta wirtualizacyjnego.

Przykład: wysoki CPU steal time w VM może wynikać nie z „za słabego procesora”, ale z przeciążenia hosta wirtualizacyjnego lub overcommitmentu CPU. Z kolei wysokie opóźnienia dysku w maszynie w chmurze mogą być skutkiem współdzielenia IOPS z innymi tenantami. Bez świadomości tej warstwy systemowe wykresy są łatwe do błędnej interpretacji.

Podstawowe narzędzia do obserwacji serwera (Linux/Windows)

Narzędzia konsolowe w systemach Linux

Linux oferuje szeroki zestaw narzędzi do szybkiego podglądu stanu serwera. Najczęściej używane:

  • top / htop – pokazują bieżące zużycie CPU, RAM, listę procesów, load average.
  • vmstat – podsumowanie pamięci, procesów, IO, systemu i CPU w krótkich odstępach czasu.
  • iostat (pakiet sysstat) – szczegółowe dane o IO: IOPS, kB/s, %util, opóźnienia.
  • sar (sysstat) – zbiera historyczne dane o CPU, IO, pamięci, sieci.
  • dstat – łączy wybrane metryki (CPU, disk, net, io, mem) w jednym widoku.
  • free – szybki podgląd pamięci (used/free/buffers/cache).
  • ps – lista procesów, często używany z filtrami (np. według CPU lub RAM).
  • perf – profilowanie na poziomie CPU (funkcje, instrukcje, cache misses).

Kluczowe jest korzystanie z tych narzędzi w formie ciągłych odczytów (np. vmstat 1, iostat -x 1), a nie pojedynczych wywołań. Zmiany w czasie (trend, skoki, korelacja) dają więcej niż jeden „kadr”.

Odpowiedniki i narzędzia w środowisku Windows

W Windows odpowiednikami linuksowych narzędzi są:

  • Task Manager – ogólny podgląd CPU, pamięci, dysku, sieci i procesów.
  • Resource Monitor – bardziej szczegółowy widok zasobów, z rozbiciem na procesy oraz pliki.
  • Performance Monitor (perfmon) – zaawansowane zbieranie liczników w czasie, możliwość logowania i tworzenia raportów.
  • PowerShell – cmdlety typu Get-Process, Get-Counter, skrypty do automatyzacji zbierania metryk.

Perfmon pozwala zdefiniować zestawy liczników (CPU, pamięć, dysk, sieć, aplikacja) i logować je do pliku, a następnie analizować po fakcie – co jest kluczowe przy diagnozie problemów, które nie występują w danej chwili, ale pojawiają się o określonych porach.

Monitoring ciągły i znaczenie danych historycznych

Narzędzia wbudowane są dobre do doraźnego oglądu. Do poważniejszej analizy potrzebny jest system monitoringu ciągłego:

  • Prometheus – zbiera metryki z exporterów, przechowuje w bazie czasowej.
  • Grafana – wizualizacja metryk w czasie, dashboardy.
  • Zabbix, Nagios, Icinga, Datadog, New Relic – inne popularne rozwiązania.

Zaletą jest możliwość:

  • porównania metryk z różnych dni/godzin,
  • korelacji zdarzeń (np. deploymenty, backupy, kampanie) z pikami CPU/IO/latency,
  • szybkiego cofnięcia się do momentu, kiedy wystąpił incydent.

Bez takiej historii administrator zwykle bazuje na szczątkach danych, zrzutach ekranu i pamięci użytkowników („chyba koło 9:15 wszystko stanęło”), co mocno utrudnia rzetelną analizę.

Ograniczenia metryk systemowych i rola APM

Same metryki CPU/RAM/dysk często nie wystarczą. Typowe sytuacje:

  • CPU jest wysycony, ale nie wiadomo, które funkcje aplikacji zużywają czas procesora.
  • IO dysku jest wysokie, ale brak informacji, które zapytania SQL generują najcięższe operacje.
  • Pamięć jest zajęta, ale trudno określić, czy to memory leak w aplikacji, czy normalny caching.

Tu wchodzą w grę narzędzia typu APM (Application Performance Monitoring) oraz profilery specyficzne dla środowiska:

APM i profilery – kiedy zejść poziom niżej niż CPU/RAM/IO

Gdy metryki systemowe pokazują „wysoki CPU” lub „dużo IO”, ale nie wiadomo, który kawałek aplikacji generuje obciążenie, przydają się:

  • APM (np. New Relic, Datadog APM, AppDynamics, Elastic APM) – śledzenie requestów od wejścia HTTP/RPC aż po bazę danych.
  • Profilery językowe (Java Flight Recorder, perf + FlameGraphs, Xdebug, dotTrace, VisualVM) – rozkład czasu CPU na metody/funkcje.
  • Monitoringi baz danych (pg_stat_statements, SQL Server DMVs, Performance Schema w MySQL) – ciężkie zapytania, blokady, plan wykonania.

Dopiero zderzenie warstwy systemowej (CPU/RAM/IO) z warstwą aplikacyjną (konkretne requesty, SQL, metody) daje szansę rzetelnie wskazać, czy „wąskie gardło CPU” to faktycznie brak rdzeni, czy po prostu jedno źle napisane zapytanie.

Kobieta z laptopem przechodzi między lustrzanymi serwerami w data center
Źródło: Pexels | Autor: Christina Morillo

Diagnoza CPU – kiedy procesor jest faktycznym problemem

Jak czytać obciążenie CPU – nie tylko „%CPU”

Pierwszy błąd to patrzenie wyłącznie na „%CPU”. Ten wskaźnik bywa mylący. Przydatniejsze są:

  • użytkowe vs systemowe zużycie CPU – w top jako us i sy, w perfmon jako Privileged Time i User Time.
  • load average (Linux) – średnia liczba zadań gotowych do wykonania (runnable) plus zadań w stanie nieprzerwalnym (często IO).
  • runnable queue – np. vmstat (kolumna r), perfmon: Processor Queue Length.

Wysokie „%CPU” przy niskim load/runnable queue oznacza zwykle, że serwer po prostu coś intensywnie robi, ale nadąża. Problem zaczyna się, gdy:

  • load average stabilnie przekracza liczbę logicznych CPU (rdzeni × HT),
  • kolejka runnable rośnie, a czasy odpowiedzi użytkowników wydłużają się.

To jest dużo mocniejszy sygnał realnego wąskiego gardła niż sam wysoki „%CPU”.

Rozkład obciążenia na rdzenie i wątki

Wielu administratorów patrzy na „średnie CPU 60%” i stawia tezę, że jest zapas. Po rozbiciu na rdzenie okazuje się, że:

  • jeden rdzeń pracuje w okolicach 100%,
  • pozostałe się nudzą.

To typowe w aplikacjach:

  • single-thread,
  • z jednym wątkiem–wąskim gardłem (np. globalny lock, sekcja krytyczna),
  • lub z niewłaściwie skonfigurowanym pool’em wątków.

Zamiast dopisywać kolejne vCPU, trzeba sprawdzić:

  • czy aplikacja potrafi skalować się na wiele rdzeni (konfiguracja wątków, procesów worker),
  • czy nie blokuje się na jednym zasobie (mutex, lock w DB, GIL w niektórych środowiskach).

Na Linuksie widać to w htop (widok per CPU), na Windows – w Task Managerze, zakładka CPU z podziałem na logiczne procesory.

CPU vs oczekiwanie na IO – mylące wysokie load average

Load average obejmuje nie tylko procesy faktycznie zużywające CPU, ale też te, które czekają na IO (dysk/sieć). Na serwerach bazodanowych to klasyczny powód paniki: „load average 30, serwer umiera”, podczas gdy:

  • %CPU nie jest wysoki,
  • spora część procesów ma stan D (uninterruptible sleep) – czeka na dysk.

Samo wysokie LA nie przesądza o wąskim gardle CPU. Jeśli widoczne są:

  • procesy w stanie D (Linux: ps aux, top),
  • niskie „us” i „sy”,
  • wysoka latencja i kolejki na dyskach (np. iostat -x),

bardziej prawdopodobne jest wąskie gardło IO niż CPU.

Identyfikacja procesów i funkcji obciążających CPU

Gdy CPU faktycznie „dochodzi do ściany”, trzeba wskazać konkretnych winowajców:

  • Linux: top, htop – sortowanie po %CPU, potem perf top / FlameGraph do zbadania funkcji.
  • Windows: Task Manager/Resource Monitor – procesy z wysokim CPU; później profiler .NET/Javy itd.

Częsty scenariusz: jeden proces Java/.NET ma 350% CPU na 4-rdzeniowej maszynie. Nie oznacza to, że „serwer jest za słaby”. Często wystarczy:

  • zoptymalizować kilka najgorzej działających zapytań SQL,
  • usunąć niepotrzebne pętle,
  • naprawić cache (np. niepotrzebne deserializacje).

Bez profilera łatwo wpaść w pułapkę rozbudowy sprzętu tam, gdzie problem jest wyłącznie programistyczny.

Specyfika środowisk wirtualnych – steal time i oversubscription

Na VM dodatkową metryką jest CPU steal time (Linux: st w top, mpstat). Wysokie wartości sygnalizują, że:

  • hipervisor nie jest w stanie przydzielić twojej maszynie tyle czasu CPU, ile prosi,
  • host jest przeciążony lub przesadnie „przeprowizjonowany” (oversubscription).

Przy wysokim steal time nawet dodanie kolejnych vCPU w VM nie pomaga, jeśli host nie ma realnego zapasu. Tu potrzebna jest współpraca z zespołem od wirtualizacji/chmury – administracja samego systemu gościa niewiele zdziała.

Diagnoza RAM – brak pamięci czy tylko niewłaściwa interpretacja metryk

Dlaczego „zajęty RAM” nie musi być problemem

W linuksowych systemach prawie cały RAM bywa oznaczany jako „wykorzystany”. To nie jest sygnał awarii, tylko:

  • cache strony/disku – system buforuje pliki, by przyspieszyć kolejne odczyty,
  • bufory – przestrzeń na dane tymczasowe.

Komenda free -m pokazuje kilka kolumn. Kluczowy jest wiersz available – ile pamięci może być natychmiast oddane procesom bez agresywnego swapowania. Jeśli:

  • used jest wysokie,
  • ale available jest wciąż sensowne,

to zwykle oznacza zdrowe wykorzystanie cache, a nie brak RAM.

Objawy realnego braku pamięci

Gdy RAM faktycznie się kończy, widać kilka sygnałów:

  • rosnące użycie swap (Linux: vmstat, free; Windows: Page File Usage),
  • wysokie wartości major page faults (Linux: vmstat, sar -B, perfmon: Page Reads/sec),
  • skokowe wydłużenie czasów odpowiedzi przy braku zmian w obciążeniu biznesowym,
  • na Linuksie – OOM killer zabijający procesy z logiem w dmesg / /var/log/messages.

Sam fakt, że swap jest „niezerowy”, nie jest jeszcze dowodem problemu. Niepokojące jest ciągłe i intensywne użycie swapu w czasie szczytu oraz korelacja z degradacją wydajności.

Swap – kiedy pomaga, a kiedy zabija wydajność

Swap to zabezpieczenie przed natychmiastową śmiercią procesów przy piku zapotrzebowania na RAM. Jednak:

  • na serwerach bazodanowych i aplikacyjnych ciągłe swapowanie potrafi spowolnić system drastycznie,
  • sam duży rozmiar swapu nie rozwiąże problemu, tylko wydłuży agonię.

Jeśli w szczycie:

  • obserwowana jest wysoka liczba page in/out,
  • czas IO dysku rośnie,
  • użytkownicy zgłaszają „nagłe zamulenie” bez zmiany liczby requestów,

bardziej racjonalne jest:

  • znalezienie procesu z nadmiernym zużyciem RAM (np. memory leak),
  • ograniczenie cache aplikacyjnych / DB,
  • lub zaplanowanie rozbudowy RAM, jeśli obciążenie jest uzasadnione.

Jak identyfikować procesy zużywające najwięcej pamięci

Standardowe podejście:

  • Linux: top / htop – sortowanie po RES lub %MEM, ps aux --sort=-rss | head.
  • Windows: Task Manager – kolumna Memory, Resource Monitor – szczegóły prywatnej pamięci roboczej.

Przy długotrwałych problemach warto zrobić pomiary w odstępach czasu. Jeśli ten sam proces:

  • stale zwiększa zajętość RAM,
  • bez wyraźnego powodu (brak wzrostu liczby użytkowników, danych),

to klasyczny wzór na memory leak. Wtedy narzędzia APM/profilery (heap dump, analizy obiektów) są koniecznością – diagnostyka na poziomie systemu kończy się na wskazaniu „to ten proces”.

Bufory i cache aplikacji vs RAM systemowy

Bazy danych, serwery cache, aplikacje JVM/.NET używają własnych mechanizmów cache. Pułapka:

  • ustawienie ogromnego cache DB/ORM,
  • na maszynie z ograniczonym RAM,
  • co wypycha resztę procesów do swapu.

Typowy przykład z praktyki: serwer z 16 GB RAM, baza skonfigurowana na 12 GB cache, JVM na 4 GB heap. Na papierze „pasuje”, w rzeczywistości system potrzebuje jeszcze pamięci na:

  • kernel,
  • cache dysku,
  • inne serwisy (logging, agent monitoringu, backup).

Efekt – przy szczycie dochodzi do swapowania mimo „teoretycznie poprawnych” ustawień. Diagnostyka w takich przypadkach musi uwzględniać sumę wszystkich rezerwacji pamięci, nie tylko pojedynczy produkt.

Specyfika pamięci w środowiskach kontenerowych

Kolejna pułapka to kontenery (Docker, Kubernetes). Metryki wewnątrz kontenera często nie pokazują, że:

  • cały node zbliża się do limitu RAM,
  • inne pody konkurują o tę samą pamięć,
  • limity requests/limits w K8s są skonfigurowane zbyt agresywnie.

Dodatkowo:

  • przekroczenie limitu pamięci w kontenerze zwykle kończy się twardym zabiciem przez OOM (bez swapu),
  • z logów aplikacji nie zawsze wynika, że powodem był OOM – informacja bywa tylko w logach kubeleta.

Diagnozując „brak pamięci” dla aplikacji w kontenerach, trzeba patrzeć:

  • na limity i requests w manifestach,
  • na metryki całego noda (RAM użyty vs allocatable),
  • na częstotliwość restarów podów i przyczynę (kubectl describe pod – OOMKilled).

Diagnoza dysku i subsystemu IO – od prostych statystyk do opóźnień

Podstawowe metryki IO: throughput, IOPS, latency, queue depth

Zasoby dyskowe mają kilka charakterystycznych parametrów:

  • throughput (MB/s) – ile danych jest przetwarzanych w czasie,
  • IOPS – liczba operacji IO na sekundę,
  • latencja – średni czas pojedynczej operacji,
  • queue depth – ile operacji czeka na obsługę.

Prosty błąd: patrzenie tylko na MB/s. HDD może mieć niski throughput, ale i tak być na granicy możliwości przez dużą liczbę losowych operacji. Z kolei szybkie SSD/NVMe utrzymają wysokie IOPS, ale przy przeciążeniu zacznie rosnąć latencja i kolejki.

Linux: iostat, sar, blktrace – praktyczne odczyty

Do oglądu IO na Linuksie:

  • iostat -x 1 – szczegółowe statystyki rozszerzone (util, svctm, await, r/s, w/s),
  • sar -d – historyczne dane o obciążeniu urządzeń blokowych,
  • iotop – procesy generujące największy IO,
  • Windows: Perfmon, Resource Monitor i narzędzia producenta storage

    Na Windowsie głównym źródłem prawdziwych danych o IO jest Performance Monitor (perfmon), a nie sam Task Manager. Task Manager potrafi zasygnalizować „wysoki dysk”, ale szczegóły są w licznikach perfmon i narzędziach producenta macierzy/RAID.

    Przy podejrzeniu wąskiego gardła dyskowego przydają się m.in.:

  • PhysicalDisk / Avg. Disk sec/Read, Avg. Disk sec/Write – realna latencja IO (sekundy na operację),
  • PhysicalDisk / Disk Reads/sec, Disk Writes/sec – liczba operacji,
  • PhysicalDisk / Disk Bytes/sec – throughput,
  • PhysicalDisk / Current Disk Queue Length – długość kolejki dla danego dysku/wolumenu,
  • LogicalDisk – podobne liczniki, ale na poziomie wolumenów logicznych.

Przy interpretacji liczb trzeba się pilnować. „Wysoka kolejka dysku” w czasach HDD była niemal automatycznym dowodem na problem, ale dla współczesnych macierzy i NVMe wysoka queue depth bywa naturalna. Bardziej wiarygodnym wyznacznikiem jest stabilnie podniesiona latencja i jej korelacja z czasami odpowiedzi aplikacji.

Drugi element układanki: oprogramowanie producenta storage (HPE, Dell, NetApp, Pure, Azure/AWS portal przy dyskach w chmurze). Te narzędzia pokazują, czy ograniczeniem jest:

  • konkretny LUN/wolumen,
  • kontroler RAID,
  • łączę do macierzy (np. iSCSI, FC),
  • polityka throttlingu IOPS/MB/s na poziomie chmury.

Przykładowo: serwer VM widzi, że „dysk” ma wysoką latencję, ale macierz pokazuje, że wszystkie inne LUN-y są w normie. Wtedy problem pojawia się zwykle w warstwie hypervisora lub przy limitach per-dysk w chmurze, a nie w samej macierzy fizycznej.

Jak odróżnić „ciężką pracę na dysku” od faktycznego wąskiego gardła

Sam fakt wysokiego obciążenia IO nic jeszcze nie znaczy. System może po prostu szybko przetwarzać dane. Wąskie gardło pojawia się dopiero wtedy, gdy:

  • latencja operacji IO rośnie i utrzymuje się wysoko pod stałym obciążeniem,
  • długość kolejki jest wysoka i skorelowana ze skargami użytkowników,
  • czasy odpowiedzi aplikacji wracają do normy wprost po spadku IO,
  • inne zasoby (CPU, RAM, sieć) pozostają w bezpiecznych zakresach.

Dobry test: obserwacja jednego endpointu lub raportu, który „mieli dysk”. Jeżeli:

  • w trakcie jego uruchomienia rośnie latencja na docelowym wolumenie (np. await w iostat albo Avg. Disk sec/Read w perfmon),
  • CPU wyraźnie spada (procesy większość czasu czekają),

to zwykle widać klasyczną sytuację „czekamy na dysk”. Jeśli natomiast CPU jest wysoko, a dysk ma niską latencję – przyczyną jest raczej kod lub baza, a nie storage.

IO wait w Linuksie – interpretacja bez automatycznych wniosków

Metryka iowait bywa nadużywana jako dowód, że „dysk jest wąskim gardłem”. Rzeczywistość jest nieco subtelniejsza. Kilka punktów kontrolnych:

  • krótkotrwałe piki iowait przy intensywnych backupach lub raportach są normalne,
  • stale wysoki iowait przy niskim wykorzystaniu CPU i wysokiej latencji IO jest znakiem, że procesy rzeczywiście czekają na dysk,
  • w systemach z kontenerami i wirtualizacją iowait na poziomie gościa nie zawsze odpowiada faktycznemu obciążeniu fizycznego storage.

Przykład z życia: serwer aplikacyjny z ~20% iowait, ale iostat pokazuje niskie wartości await, a SSD działają w granicach specyfikacji. Okazuje się, że proces generuje wiele małych odczytów w krótkich burstach, przeplatanych długimi sekcjami CPU-bound. Średni iowait jest „wysoki”, lecz nie odzwierciedla trwałego zablokowania systemu na dysku. Kontekst i korelacja z innymi metrykami są ważniejsze niż sam procent.

Wzorce obciążenia IO: sekwencyjne, losowe, małe i duże bloki

Nie każdy intensywny IO jest równie „trudny” dla infrastruktury. Ten sam throughput może być łatwy dla macierzy w postaci sekwencyjnego strumienia, a zabójczy jako zbiór losowych operacji na małych blokach.

Przy analizie podział IO na:

  • sekwencyjny vs losowy – bazy danych z dużą ilością małych losowych zapisów, logi z sekwencyjnym dopisywaniem,
  • małe vs duże bloki – np. 4 KB vs 1 MB; małe bloki podbijają IOPS, ale nie throughput,
  • read vs write heavy – różne systemy storage inaczej reagują na przewagę zapisów (np. poziom cache, write-back vs write-through).

Jeżeli dostawca macierzy deklaruje „do X IOPS”, zwykle zakłada konkretne parametry (wielkość bloku, mix R/W). Prawdziwe obciążenie aplikacji bywa od tego odległe, więc surowe tabelki marketingowe rzadko pomagają. Lepiej zestawić:

  • realne IOPS i latency z iostat/perfmon,
  • informacje od producenta (np. testy fio przy podobnym profilu IO),
  • obserwacje z czasu zmian – jak reaguje storage, gdy dołożymy kolejny komponent generujący IO.

Wąskie gardła IO w środowiskach wirtualnych i chmurowych

Na VM oraz w chmurze trzeba brać poprawkę na dodatkowe warstwy pomiędzy serwerem a fizycznym dyskiem:

  • hypervisor z własną kolejką i schedulerem IO,
  • warstwę sieciową (iSCSI, NFS, SMB, wirtualne dyski w chmurze),
  • limity IOPS/MB/s na poziomie dysku, subskrypcji, a nawet regionu.

Typowy scenariusz w chmurze: VM ma dysk, który wg specyfikacji powinien „udźwignąć” określoną liczbę IOPS. W praktyce:

  • przy burstach osiąga deklarowane wartości,
  • po wyczerpaniu kredytów przepustowości spada do niższego poziomu,
  • aplikacja obserwuje skokową degradację.

Sama VM „nie wie”, że wyczerpała burst credits. Ogólny wniosek pojawia się dopiero przy korelacji z metrykami platformy (Azure Monitor, CloudWatch, etc.) oraz dokumentacją typu „IOPS baseline/burst”.

Podobny problem w on-premise: kilka wirtualek z intensywnym IO współdzieli ten sam datastore. Każda z osobna wygląda „w miarę zdrowo”, ale sumaryczne obciążenie saturuje macierz. Tylko widok z poziomu hypervisora lub systemu storage pokaże, że wszystkie VM razem przekraczają możliwości urządzenia.

Jak namierzyć procesy i zapytania generujące nadmierny IO

Po stwierdzeniu, że storage jest ograniczeniem, następny krok to identyfikacja źródła. W praktyce ścieżka bywa podobna:

  • Linux: iotop lub pidstat -d – które PID-y generują najwięcej odczytów/zapisów,
  • Windows: Resource Monitor (zakładka Disk) – procesy i pliki z największym transferem i IOPS,
  • bazy danych: widoki systemowe (np. w SQL Server: sys.dm_io_virtual_file_stats, w Postgresie: pg_stat_io / rozszerzenia monitorujące) – które tabele/indeksy i zapytania produkują najwięcej IO.

Po wskazaniu procesu trzeba zejść w głąb:

  • jeśli to baza – identyfikacja raportów i zapytań z dużymi skanami tabel, brakującymi indeksami,
  • jeśli to aplikacja – sprawdzenie, czy nie otwiera plików w pętli, czy nie serializuje nadmiernie danych,
  • jeśli to backup/antywirus – korekta harmonogramu i priorytetów, by nie kolidowały z godzinami szczytu.

Przykład: okresowe „zwiechy” podczas nocnego okna. Monitoring storage wskazuje duże sekwencyjne zapisy, iotop – proces backupu, a w logach aplikacji widać błędy timeoutu. Rozwiązanie nie wymaga nowej macierzy, tylko przesunięcia okna backupu lub przeniesienia go na drugi serwer.

Kiedy sprzęt jest naprawdę zbyt słaby, a kiedy problem jest logiczny

Ostatni etap diagnozy IO to odpowiedź na niewygodne pytanie: czy infra fizycznie nie wyrabia, czy obciążenie jest po prostu źle zaprojektowane. Kilka sygnałów, że sprzęt zbliża się do ściany:

  • latencja IO rośnie prawie liniowo z obciążeniem, bez wyraźnego „progu optymalizacji”,
  • brak jednej aplikacji/procesu dominującego IO – prawie każdy komponent dokłada swoją cegiełkę,
  • macierz/hypervisor raportuje wysoki poziom „busy” na wszystkich kontrolerach/dyskach.

Z drugiej strony, jeśli:

  • 90% IO generuje jedna tabela raportowa,
  • profil zapytań pokazuje wiele pełnych skanów i brak indeksów,
  • zmiana kilku zapytań dwukrotnie zmniejsza IOPS i latencję,

oznacza to raczej problem logiczny (projekt danych, indeksy, cache) niż czysto sprzętowy. Dołożenie SSD może zamaskować błąd projektowy na chwilę, ale przy dalszym wzroście ruchu sytuacja wróci.

Łączenie diagnozy CPU, RAM i IO w jedną historię

CPU, RAM i dysk rzadko działają w izolacji. Prawdziwe wąskie gardła najczęściej pokazują się jako wspólny wzorzec kilku metryk. Przykładowe kombinacje:

  • CPU wysoki, IO niskie, RAM stabilny – procesor jest realnym ograniczeniem lub kod robi kosztowne operacje w pamięci; trzeba profilowania, a nie szybszego storage,
  • CPU niskie, IO wysokie, latencja rośnie – czekamy na dysk; sensowne są korekty zapytań, reorganizacja danych, przebudowa indeksów lub zmiana profilu IO,
  • wysokie IO + rosnące swapowanie – braki RAM powodują uderzanie w dysk; często skuteczniejsza jest optymalizacja pamięciowa niż inwestycja w macierz,
  • nagłe piki CPU i IO bez zmian ruchu – zadania okresowe, backupy, odśmiecanie cache, reorganizacja indeksów; warto przejrzeć harmonogramy i okna serwisowe.

Dobry proces diagnostyczny nie szuka „jednego winnego”, tylko sprawdza, jak zachowują się wszystkie trzy główne zasoby pod tym samym obciążeniem biznesowym. Dopiero z takiego obrazu widać, czy wymiana serwera ma sens, czy raczej potrzebna jest zmiana konfiguracji lub refaktoryzacja fragmentu systemu.

Najczęściej zadawane pytania (FAQ)

Jak rozpoznać, że mam wąskie gardło CPU, a nie „po prostu wysokie użycie procesora”?

Wąskie gardło CPU masz wtedy, gdy przy wzroście obciążenia (więcej użytkowników, równoległych zapytań, zadań batch) przepustowość przestaje rosnąć, a czas odpowiedzi rośnie wykładniczo. Samo 80–90% użycia CPU nie jest problemem, jeśli API nadal odpowiada szybko, a liczba obsłużonych żądań rośnie w miarę liniowo.

Praktyczny test: porównaj wykresy użycia CPU z wykresami czasów odpowiedzi i błędów. Jeśli CPU jest „na czerwono”, ale SLA jest spełnione i nie ma skoków opóźnień – to raczej efektywne wykorzystanie zasobów, a nie wąskie gardło. Jeśli przy tym obciążenie rośnie, a throughput „staje w miejscu”, wtedy CPU jest dobrym kandydatem na winowajcę.

Jak sprawdzić, czy brakuje RAM, czy to tylko systemowy cache pamięci?

Typowy błąd: patrzenie tylko na „wolną pamięć” i wniosek „RAM jest zapchany”. Nowoczesne systemy (szczególnie Linux) zjadają RAM na cache i buffery, co jest pożądane. Sygnałem realnego problemu jest dopiero intensywne korzystanie ze swapu oraz skokowa degradacja czasów odpowiedzi.

W praktyce sprawdź:

  • czy rośnie użycie swapu i liczba page faults (vmstat, perfmon),
  • czy w momentach problemów pojawia się masowe przerzucanie stron do/z dysku,
  • czy po wyłączeniu lub ograniczeniu pamięciożernych procesów opóźnienia spadają.
  • Jeśli RAM jest „pełny”, ale swap prawie nieużywany, a system reaguje stabilnie, to raczej nie jest wąskie gardło pamięci.

Jak odróżnić wąskie gardło dysku od problemu z aplikacją lub bazą danych?

Wąskie gardło IO objawia się przede wszystkim rosnącą latencją operacji dyskowych i wydłużającymi się kolejkami, a nie samą liczbą IOPS. Możesz mieć bardzo „wysokie” IO i nadal brak problemów, jeśli opóźnienia pozostają przewidywalne.

Spójrz na:

  • metryki dysku: latency, queue depth, czas oczekiwania na IO (iostat, narzędzia vendorów storage),
  • czasy wykonania zapytań w bazie vs czasy odpowiedzi aplikacji,
  • czy opóźnienia rosną głównie podczas backupów, raportów, batchy.
  • Jeżeli dysk ma spokojne opóźnienia, a mimo to konkretne transakcje wiszą na blokadach lub GC, problem leży raczej w logice aplikacji lub konfiguracji bazy, a nie w samym storage.

Czy wysokie zużycie CPU lub RAM zawsze oznacza, że serwer jest „za słaby” i trzeba kupić nowy sprzęt?

Nie. Wysokie wykorzystanie zasobów przy zachowaniu SLA jest oznaką, że sprzęt pracuje efektywnie. Inwestycja w mocniejszy serwer ma sens tylko wtedy, gdy:

  • czasy odpowiedzi są poza akceptowalnym zakresem,
  • obciążenie jest typowe (nie incydentalny szczyt),
  • optymalizacja aplikacji i konfiguracji została chociaż wstępnie przeanalizowana.

Często taniej i skuteczniej jest:

  • przeplanować raporty i zadania batch na inne godziny,
  • poprawić zapytania SQL lub konfigurację puli wątków,
  • usunąć zbędne procesy na tym samym hoście.
  • Stwierdzenie „serwer jest za słaby” bez twardych metryk i korelacji z objawami biznesowymi to uproszczenie, które łatwo prowadzi do przepalenia budżetu.

Jak znaleźć wąskie gardło, gdy użytkownicy mówią tylko „system działa wolno”?

Pierwszy krok to doprecyzowanie objawów w języku biznesu, a nie technicznym. Dopytaj: co dokładnie działa wolno (logowanie, wyszukiwanie, raporty, konkretne API), kiedy (konkretne godziny, dni miesiąca), jak długo trwa operacja teraz i jaki jest oczekiwany czas. Bez tego każda analiza metryk to zgadywanie.

Dopiero do tak opisanych symptomów doklejasz metryki: szukasz w tych samych oknach czasowych anomalii CPU, RAM, IO, sieci i metryk aplikacji. Jeśli problemy pojawiają się wyłącznie przy generowaniu dużych raportów, a zwykłe transakcje są szybkie, podejrzenie pada raczej na konflikt zadań/raportów lub kiepskie zapytania niż ogólne przeciążenie całego serwera.

Jak odróżnić wąskie gardło stałe od okresowego lub sezonowego?

Kluczowe jest spojrzenie na historię metryk, a nie jednorazowy zrzut z top czy Task Managera. Wąskie gardło stałe widać jako niemal permanentne wysokie użycie zasobu (CPU, IO, swap, latency) w typowych godzinach pracy. Okresowe – jako powtarzalne „górki” w tych samych oknach (np. codziennie 8–10 rano). Sezonowe – jako skoki w specyficznych dniach czy kampaniach.

Bez monitoringu z historią łatwo dojść do błędnych wniosków. Przykład z praktyki: administrator patrzy na przeciążony serwer o 2:00 w nocy i wnioskuje „dysk nie wyrabia”. Po przejrzeniu tygodni z monitoringiem okazuje się, że tylko backup i reindeksacja odpalane równocześnie tworzą krótkie, ostre wąskie gardło – w ciągu dnia system działa poprawnie. Rozwiązaniem jest przeplanowanie zadań, a nie od razu rozbudowa storage.

Jakimi narzędziami w Linux/Windows najszybciej wychwycić, gdzie jest wąskie gardło?

Na Linuksie pierwsza linia to:

  • top/htop – ogólne zużycie CPU, RAM, procesy, load average,
  • vmstat – procesy, pamięć, IO, CPU w krótkich odstępach czasu,
  • iostat – szczegółowe statystyki IO, w tym opóźnienia i kolejki.
  • Te narzędzia pozwalają szybko sprawdzić, czy procesy stoją w kolejce do CPU, czy system swapuje, czy dysk ma wysoką latencję w momentach, gdy użytkownicy skarżą się na wolne działanie.

W Windows punkt startowy to:

  • Task Manager/Resource Monitor – bieżące obciążenie CPU, RAM, dysk, sieć,
  • Performance Monitor (perfmon) – zbieranie dłuższej historii metryk (CPU, RAM, Physical Disk, Network Interface).
  • Samo odpalenie narzędzia „po fakcie” jest mało miarodajne. Najwięcej daje ciągły monitoring z historią, który można nałożyć na godziny zgłaszanych problemów i dopiero wtedy szukać realnego wąskiego gardła.