Linux OOM Killer Tuning dla VPS: Praktyczny przewodnik

12 min czytania - 8 czerwca 2026

hero section cover
Spis treści
  • Dostrajanie zabójcy OOM w systemie Linux dla VPS
  • Jak OOM killer wybiera ofiarę
  • Wykrywanie obciążenia pamięci przed awarią
  • Ochrona krytycznych procesów za pomocą oom_score_adj
  • Ograniczanie pamięci za pomocą cgroups i systemd
  • Czytanie logów po zdarzeniu OOM
  • Podsumowanie
Udostępnij

Dostosuj Linux OOM killer na swoim serwerze VPS, aby chronić bazy danych i SSH, ograniczyć niekontrolowane procesy za pomocą cgroups i powstrzymać niewłaściwą usługę przed zabiciem.

Dostrajanie zabójcy OOM w systemie Linux dla VPS

Linux OOM killer to ostatnia deska ratunku jądra, gdy zabraknie pamięci: wybiera proces i kończy go, aby utrzymać system przy życiu. Na VPS, gdzie pamięć RAM jest ograniczona i nie ma gdzie się wycofać, domyślny wybór jest często zły. Twoja baza danych zostaje zabita, długo działający proces przetrwa, a ty musisz sam dowiedzieć się, dlaczego. Ten przewodnik opisuje, jak OOM killer ocenia procesy, jak nastawić tę ocenę na swoje krytyczne usługi oraz jak używać cgroups, aby pojedynczy proces nie mógł pociągnąć za sobą reszty systemu.


 

Jak OOM killer wybiera ofiarę

Gdy jądro nie może odzyskać wystarczającej ilości pamięci poprzez usuwanie z pamięci podręcznej stron lub wymianę na dysk, uruchamia OOM killer. Każdy proces ma oom_score wartość z przedziału od 0 do 1000, wyznaczaną głównie na podstawie jego rozmiaru zestawu rezydentów (RSS) oraz wykorzystania przestrzeni wymiany. Proces o najwyższym wyniku otrzymuje sygnał SIGKILL.

RSS dominuje w obliczeniach, dlatego zabicie prawie zawsze dotyka największego konsumenta pamięci. Często jest to baza danych, serwer aplikacji lub dowolny długotrwały proces, który wykonuje najbardziej użyteczną pracę. Proces, który faktycznie wywołał alokację, „wywołujący”, rzadko jest tym, który zostaje zakończony.

Istnieją dwa rodzaje zdarzeń OOM, które należy rozróżniać:

  • Globalny OOM: host (lub cały serwer VPS) nie ma już pamięci RAM ani pamięci wymiany. Jądro skanuje każdy proces i zabija ten z najwyższym wynikiem.
  • OOM cgroup: konkretna grupa cgroup osiągnęła limit pamięci. Jądro zabija procesy tylko w tej grupie cgroup, nawet jeśli reszta systemu ma wolną pamięć.

Jeśli skonfigurowałeś limity jednostek systemd lub uruchamiasz kontenery, większość zdarzeń OOM będzie miała charakter cgroup OOM. To dobrze: zasięg wybuchu jest ograniczony.

Wykrywanie obciążenia pamięci przed awarią

Zdarzenia OOM prawie nigdy nie są nagłe. Zazwyczaj najpierw pojawia się okres narastającego obciążenia, a celem monitorowania jest wykrycie go w tym okresie.

free -h daje widok systemowy. Kolumna, która ma znaczenie, to available, a nie free: uwzględnia ona odzyskiwalną pamięć podręczną stron i odzwierciedla to, co faktycznie można przydzielić bez wymiany. Utrzymuj MemAvailable na poziomie około 10–15 procent MemTotal przy szczytowym obciążeniu.

Aby uzyskać przypisanie na proces, posortuj według RSS:

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

Lub użyj htop i posortuj według RES. Wartości widoczne w tym miejscu są bezpośrednio uwzględniane w ocenie jądra, więc najwyższe pozycje to najbardziej prawdopodobne cele OOM.

W jądrach 4.20 i nowszych, Pressure Stall Information to system wczesnego ostrzegania, który warto włączyć do monitorowania:

cat /proc/pressure/memory

Wartość some avg10 Wartość ta to procent czasu, w którym co najmniej jedno zadanie utknęło w oczekiwaniu na pamięć w ciągu ostatnich dziesięciu sekund. Wynik poniżej 5 procent jest w porządku. Trwałe wartości powyżej 10 procent oznaczają, że system spędza rzeczywisty czas zablokowany na odzyskiwaniu pamięci, a zabicie z powodu braku pamięci (OOM) jest prawdopodobne.

Swap thrashing pojawia się w vmstat 1 jako niezerowe si i so kolumnach utrzymujących się w czasie. Niewielka ilość rezydentnej pamięci wymiany jest nieszkodliwa. Ciągłe wczytywanie i wypisywanie z pamięci wymiany już nie.

Ochrona krytycznych procesów za pomocą oom_score_adj

Wynik obliczany przez jądro może być dostosowany dla poszczególnych procesów za pomocą oom_score_adj, w skali od -1000 (odporny) do +1000 (zabij mnie jako pierwszego). Korekta jest dodawana bezpośrednio do wyniku końcowego.

Aby wprowadzić jednorazową zmianę w stosunku do uruchomionego procesu:

echo -500 | sudo tee /proc/$(pidof sshd)/oom_score_adj

W przypadku wszystkiego, co chcesz zachować po ponownym uruchomieniu, ustaw to w jednostce systemd. To właściwe miejsce dla sshd, twojej bazy danych i wszystkiego innego, czego nie możesz stracić:

[Service]
OOMScoreAdjust=-900

Rozsądne wartości domyślne na początek:

  • sshd: -1000. Jeśli utracisz zdalny dostęp podczas kryzysu pamięci, przywrócenie systemu będzie znacznie trudniejsze.
  • MySQL, PostgreSQL, Redis: od -800 do -900. Silna ochrona bez czynienia ich całkowicie nietykalnymi w naprawdę katastrofalnej sytuacji.
  • Procesy aplikacji, zadania wsadowe, zadania cron: +100 do +500. Są to procesy, które lepiej zabić niż bazę danych.

Nie ustawiaj wszystkiego na -1000. Jeśli nic nie będzie można zamknąć, jądro w końcu wpadnie w panikę lub zawiesi się, co jest jeszcze gorsze.

Ograniczanie pamięci za pomocą cgroups i systemd

Dostosowanie wyników wpływa na to, kto zostanie wyłączony. Grupy cgroup wpływają na to, czy globalne wyłączenie w ogóle nastąpi. Nadając każdej usłudze sztywny górny limit, przenosisz awarie pamięci do jednej grupy cgroup, zamiast pozwalać, by jeden proces wyczerpał cały VPS.

W pliku jednostki systemd:

[Service]
MemoryHigh=400M
MemoryMax=512M
OOMPolicy=stop
Restart=on-failure
RestartSec=5s

MemoryHigh jest miękkim ograniczeniem: jądro agresywnie odzyskuje strony z cgroup powyżej tego punktu, ale niczego nie zabija. MemoryMax jest twardym pułapem. Jeśli cgroup próbuje przydzielić pamięć powyżej tego pułapu, jądro zabija proces wewnątrz cgroup. Dzięki Restart=on-failure usługa uruchamia się ponownie natychmiast.

W cgroup v2 (Ubuntu 22.04 i nowsze, najnowsze wersje Debiana, RHEL 9), memory.oom.group zabija wszystkie procesy w cgroup jednocześnie, zamiast pozostawiać osierocone procesy. Przydatne w przypadku usług wieloprocesowych, takich jak pule PHP-FPM, gdzie grupa zabita tylko w połowie będzie działać nieprawidłowo.

Kilka uwag dotyczących konkretnych aplikacji, które warto zastosować:

  • PHP-FPM: ustaw pm = ondemand na małych instancjach VPS i ustaw pm.max_children w oparciu o średnią wartość RSS na pracownika, a nie wartość domyślną. Pula o wielkości 4 GB na 2 GB VPS spowoduje błąd OOM przy pierwszym zapełnieniu.
  • Node.js: ogranicz stertę V8 za pomocą --max-old-space-size=512 (w MB). Bez tego Node będzie się rozrastał, aż wkroczy jądro.
  • MySQL i PostgreSQL: innodb_buffer_pool_size oraz shared_buffers powinny pozostawić wystarczającą rezerwę dla pamięci podręcznej stron systemu operacyjnego, pamięci połączeń oraz innych użytkowników na serwerze. Ustawienia domyślne zakładają serwer dedykowany.

Czytanie logów po zdarzeniu OOM

Kiedy uruchamia się OOM killer, jądro zapisuje szczegółowy raport w buforze pierścieniowym. Wyciągnij go za pomocą:

dmesg -T | grep -iE 'killed process|out of memory'
journalctl -k --grep='Out of memory'

Blok, który należy uważnie przeczytać, zaczyna się od wywołującego, a kończy na ofierze. Jądro wyświetla pełną listę zadań wraz z RSS każdego procesu, wykorzystaniem pamięci wymiany i końcowym oom_score_adj. Warto sprawdzić trzy rzeczy:

  • Ograniczenie. CONSTRAINT_NONE oznacza globalny OOM, CONSTRAINT_MEMCG oznacza, że cgroup osiągnął swój limit. Rozwiązanie jest inne w każdym przypadku.
  • Free swap. Jeśli to jest 0kB, to wyczerpała się zarówno pamięć RAM, jak i partycja swap. Należy albo dodać partycję swap, zwiększyć MemoryMax na procesie, który to spowodował, albo zmniejsz współbieżność.
  • Wynik ofiary w porównaniu z resztą. Jeśli wynik ofiary nie jest dużo wyższy od wyników kilku następnych procesów, oom_score_adj wartości nie są wystarczające. Zwiększ różnicę.

W przypadku konkretnie OOM-ów cgroup licznik zabitych procesów znajduje się memory.events wewnątrz cgroup:

cat /sys/fs/cgroup/system.slice/mysql.service/memory.events

Rosnąca oom_kill liczby oznacza, że usługa wielokrotnie osiąga swój limit. To sygnał, aby zwiększyć MemoryMax, przeanalizować obciążenie lub przenieść usługę do większego planu, a nie ciągle ją restartować w pętli.

Podsumowanie

Dostrajanie mechanizmu OOM killer nie polega na jego wyłączeniu. Chodzi o kontrolowanie, który proces poniesie koszty w przypadku wyczerpania pamięci, oraz o ograniczenie zasięgu skutków, gdy do tego dojdzie. Schemat, który sprawdza się w środowisku produkcyjnym:

  • Zabezpiecz usługi, których utraty nie możesz sobie pozwolić, zwłaszcza sshd i bazy danych.
  • Ogranicz wszystko inne za pomocą MemoryMax w jednostce systemd, tak aby pojedynczy awaria oznaczała jedynie ponowne uruchomienie, a nie całkowitą przerwę w działaniu.
  • Obserwuj PSI i MemAvailable zamiast czekać na dmesg , aż poinformuje Cię o tym po fakcie.
  • Zostaw 15–20 procent pamięci RAM jako rezerwę. Optymalizacja nie zrekompensuje VPS-a, który jest po prostu zbyt mały dla danego obciążenia.

Jeśli obciążenie pamięci ma charakter strukturalny, a nie wynika z konfiguracji, potrzebujesz więcej pamięci RAM lub szybszej pamięci wymiany. Plany VPS firmy FDC Servers działają na procesorach AMD EPYC z pamięcią NVMe, co zapewnia wystarczającą szybkość odczytu z pamięci wymiany, dzięki czemu krótkotrwałe skoki obciążenia pamięci nie eskalują do wyłączeń.

Blog

Polecane w tym tygodniu

Więcej artykułów
Linux OOM Killer Tuning dla VPS: Praktyczny przewodnik

Linux OOM Killer Tuning dla VPS: Praktyczny przewodnik

Dostosuj Linux OOM killer na swoim serwerze VPS, aby chronić bazy danych i SSH, ograniczyć niekontrolowane procesy za pomocą cgroups i powstrzymać niewłaściwą usługę przed zabiciem.

12 min czytania - 8 czerwca 2026

Linux Traffic Control (tc): praktyczny przewodnik

12 min czytania - 5 czerwca 2026

Więcej artykułów
background image

Masz pytania lub potrzebujesz niestandardowego rozwiązania?

icon

Elastyczne opcje

icon

Globalny zasięg

icon

Natychmiastowe wdrożenie

icon

Elastyczne opcje

icon

Globalny zasięg

icon

Natychmiastowe wdrożenie