Linux OOM Killer — zabójca procesów, którego musisz znać
Twój system ma własnego zabójcę
Gdzieś głęboko w jądrze Linuksa istnieje mechanizm, którego jedynym zadaniem jest zabijanie procesów. Nie pyta o pozwolenie. Nie wysyła grzecznego powiadomienia. Kiedy systemowi kończy się pamięć i nie ma absolutnie żadnego innego wyjścia, do akcji wkracza OOM Killer (Out of Memory Killer) i zamyka wybrany proces, aby zwolnić RAM.
Brzmi brutalnie? Bo tak jest. Ale alternatywa jest gorsza – kompletnie zamrożony system, który nie robi nic. OOM Killer to ostatnia deska ratunku jądra, mechanizm przetrwania, który poświęca jeden proces, żeby reszta systemu mogła działać dalej.
Jak wybiera swoją ofiarę?
OOM Killer nie działa losowo. Każdy uruchomiony proces w systemie ma przypisany wynik zwany oom_score. Im wyższy wynik, tym większe prawdopodobieństwo, że proces zostanie zabity. Jądro oblicza ten wynik na podstawie kilku czynników, ale najważniejszy z nich jest prosty: ile pamięci zużywa proces?
Proces pochłaniający 4 GB RAM będzie miał znacznie wyższy wynik niż ten, który używa 20 MB. Jądro bierze też pod uwagę, jak długo proces działa i czy należy do roota.
Możesz sprawdzić OOM score dowolnego procesu:
# Zastąp PID rzeczywistym numerem procesu
cat /proc/PID/oom_score
Praktyczny przykład – sprawdźmy wynik naszej bieżącej powłoki:
cat /proc/$$/oom_score
Prawdopodobnie zobaczysz niewielką liczbę. Teraz spróbuj sprawdzić przeglądarkę z 47 otwartymi kartami – ten wynik będzie znacznie wyższy.
Jak chronić proces przed zabiciem?
Czasem masz proces, który absolutnie nie może zostać zabity. Na przykład serwer bazy danych. Możesz powiedzieć jądru, żeby go nie ruszało, zmieniając wartość oom_score_adj.
Wartość oom_score_adj mieści się w zakresie od -1000 do 1000. Ustawienie jej na -1000 sprawia, że proces jest praktycznie odporny na OOM Killera:
# Ochrona procesu (zastąp PID rzeczywistym numerem procesu)
echo -1000 | sudo tee /proc/PID/oom_score_adj
Odwrotnie, jeśli chcesz, żeby dany proces był pierwszym do odstrzału:
# Ustawienie procesu jako preferowanego celu
echo 1000 | sudo tee /proc/PID/oom_score_adj
Pamiętaj, że to ustawienie nie przeżywa restartu systemu. Aby zmiana była trwała, możesz ustawić OOMScoreAdjust=-1000 w pliku usługi systemd.
Jak zobaczyć zabójstwa OOM w logach?
Kiedy OOM Killer uderza, zostawia ślady. Możesz je znaleźć w dmesg:
dmesg | grep -i "oom"
Typowy komunikat o zabiciu procesu przez OOM wygląda mniej więcej tak:
[ 234.567890] Out of memory: Killed process 1234 (some-app) total-vm:4567892kB, anon-rss:3210456kB
Mówi to dokładnie, który proces został zabity, ile pamięci wirtualnej miał zarezerwowanej i ile pamięci fizycznej (RSS) faktycznie używał. Jeśli widzisz takie komunikaty regularnie, Twój system ma problem z pamięcią, który wymaga uwagi.
Możesz też sprawdzić dziennik systemowy:
journalctl -k | grep -i "oom"
Wywołanie OOM celowo (nie rób tego na produkcji)
Dla ciekawskich – i wyłącznie na testowej maszynie, na której nic Ci nie zależy – możesz wywołać OOM Killera celowo. Oto prosty pożeracz pamięci w Pythonie:
# UWAGA: To SPOWODUJE zabijanie procesów w Twoim systemie.
# Uruchamiaj to tylko na jednorazowej testowej maszynie wirtualnej.
python3 -c "a = []; [a.append(' ' * 10**6) for _ in iter(int, 1)]"
Możesz też zaobserwować zachowanie OOM przy klasycznej fork bombie, ale serio, nie uruchamiaj tego na niczym ważnym:
# NIE uruchamiaj tego na systemie produkcyjnym. Zostałeś ostrzeżony.
:(){ :|:& };:
Wspominam o tym nie po to, żeby zachęcać do chaosu, ale żeby pomóc Ci zrozumieć, co się dzieje, gdy pamięć się wyczerpie. Jeśli testujesz to na VM, obserwuj dmesg -w w drugim terminalu, żeby zobaczyć OOM Killera w akcji.
Szybkie porady, jak unikać problemów z OOM
Oto kilka praktycznych rzeczy, które możesz zrobić, aby Twój system nie dochodził do stanu OOM:
- Monitoruj zużycie pamięci. Narzędzia takie jak
htop,vmstatczyfree -hto Twoi przyjaciele. Nie czekaj, aż jądro poinformuje Cię o problemie. - Ustawiaj limity pamięci. Użyj cgroups lub dyrektywy
MemoryMaxw systemd, aby ograniczyć ile RAM może zużyć dana usługa. - Skonfiguruj swap. Swap nie zastępuje RAM, ale daje systemowi chwilę oddechu, zanim OOM Killer będzie musiał interweniować.
- Sprawdzaj aplikacje pod kątem wycieków pamięci. Proces, który powoli pożera cały RAM przez dni lub tygodnie, to klasyczny powód wywołania OOM.
- Używaj
oom_score_adjrozsądnie. Chroń krytyczne usługi, ale nie chroń wszystkiego – jeśli nic nie może być zabite, cały system się zablokuje.
Na koniec
OOM Killer to nie błąd. To nie wada. To świadoma decyzja projektowa, która utrzymuje systemy Linux przy życiu, gdy sprawy idą źle. Zrozumienie jego działania stawia Cię w znacznie lepszej pozycji do zarządzania systemami, chronienia krytycznych usług i debugowania tych tajemniczych incydentów typu “mój proces po prostu zniknął”.
Następnym razem, gdy proces zniknie bez śladu, sprawdź dmesg. OOM Killer może mieć coś do wyznania.