Kiedy serwer bazy danych w systemie Linux nieoczekiwanie kończy działanie, należy znaleźć przyczynę. Powodów może być kilka. Na przykład, SIGSEGV — awaria spowodowana błędem na serwerze zaplecza. Ale to jest rzadkie. Najczęściej po prostu brakuje Ci miejsca na dysku lub pamięci. Jeśli zabraknie Ci miejsca na dysku, jest tylko jedno wyjście - zwolnij miejsce i zrestartuj bazę danych.
Zabójca bez pamięci
Gdy w serwerze lub procesie zabraknie pamięci, Linux oferuje 2 rozwiązania: awarię całego systemu lub zakończenie procesu (aplikacji), który pochłania pamięć. Lepiej oczywiście zakończyć proces i uchronić system operacyjny przed awarią. W skrócie Out-Of-Memory Killer to proces, który zabija aplikację, aby uchronić jądro przed awarią. Poświęca aplikację, aby utrzymać działanie systemu operacyjnego. Omówmy najpierw, jak działa OOM i jak nim sterować, a następnie zobaczmy, jak OOM Killer decyduje, którą aplikację zakończyć.
Jednym z głównych zadań Linuksa jest przydzielanie pamięci procesom, gdy o to proszą. Zwykle proces lub aplikacja żąda pamięci od systemu operacyjnego, ale nie wykorzystuje jej w pełni. Jeśli system operacyjny udostępni pamięć każdemu, kto o nią poprosi, ale nie planuje jej używać, wkrótce pamięć się skończy i system ulegnie awarii. Aby tego uniknąć, system operacyjny rezerwuje pamięć dla procesu, ale tak naprawdę jej nie zwalnia. Pamięć jest przydzielana tylko wtedy, gdy proces faktycznie będzie z niej korzystał. Zdarza się, że system operacyjny nie ma wolnej pamięci, ale przydziela ją procesowi, a gdy proces jej potrzebuje, system operacyjny przydziela ją, jeśli może. Minusem jest to, że czasami system operacyjny rezerwuje pamięć, ale we właściwym czasie nie ma wolnej pamięci i system ulega awarii. OOM odgrywa ważną rolę w tym scenariuszu i kończy procesy, aby zapobiec panice jądra. Kiedy proces PostgreSQL zostanie zmuszony do zakończenia, w dzienniku pojawia się komunikat:
Out of Memory: Killed process 12345 (postgres).
Jeżeli w systemie brakuje pamięci i nie można jej zwolnić, funkcja jest wywoływana out_of_memory
. Na tym etapie pozostaje jej już tylko jedno – ukończyć jeden lub więcej procesów. Czy OOM-killer powinien natychmiast zakończyć proces, czy może poczekać? Oczywiście wywołanie out_of_memory wynika z oczekiwania na operację we/wy lub stronicowanie na dysk. Dlatego też zabójca OOM musi najpierw przeprowadzić kontrole i na ich podstawie podjąć decyzję o konieczności zakończenia procesu. Jeśli wszystkie poniższe kontrole wypadną pozytywnie, OOM zakończy proces.
Wybór procesu
Gdy skończy się pamięć, funkcja zostanie wywołana out_of_memory()
. Ma funkcję select_bad_process()
, który otrzymuje ocenę od funkcji badness()
. Celem będzie „najgorszy” proces. Funkcjonować badness()
wybiera proces według określonych reguł.
- Jądro potrzebuje dla siebie minimalnej ilości pamięci.
- Musisz zwolnić dużo pamięci.
- Nie ma potrzeby kończenia procesów, które zużywają mało pamięci.
- Należy ukończyć minimalne procesy.
- Złożone algorytmy zwiększające szanse na realizację procesów, które sam użytkownik chce zakończyć.
Po zakończeniu wszystkich tych kontroli OOM sprawdza wynik (oom_score
). OOM przydziela oom_score
każdego procesu, a następnie mnoży tę wartość przez ilość pamięci. Procesy o większych wartościach częściej padają ofiarą OOM Killera. Procesy powiązane z użytkownikiem root mają niższy wynik i jest mniej prawdopodobne, że zostaną zmuszone do zakończenia.
postgres=# SELECT pg_backend_pid();
pg_backend_pid
----------------
3813
(1 row)
Identyfikator procesu Postgres to 3813, więc w innej powłoce można uzyskać wynik za pomocą tego parametru jądra oom_score
:
vagrant@vagrant:~$ sudo cat /proc/3813/oom_score
2
Jeśli nie chcesz, aby OOM-Killer w ogóle zakończył proces, istnieje inna opcja jądra: oom_score_adj
. Dodaj dużą wartość ujemną, aby zmniejszyć szanse na zakończenie cenionego procesu.
sudo echo -100 > /proc/3813/oom_score_adj
Aby ustawić wartość oom_score_adj
, ustaw OOMScoreAdjust w bloku serwisowym:
[Service]
OOMScoreAdjust=-1000
Albo użyj oomprotect
w zespole rcctl
.
rcctl set <i>servicename</i> oomprotect -1000
Wymuś zakończenie procesu
Gdy jeden lub więcej procesów jest już wybranych, OOM-Killer wywołuje tę funkcję oom_kill_task()
. Funkcja ta wysyła do procesu sygnał zakończenia. W przypadku braku pamięci oom_kill()
Wywołuje tę funkcję, aby wysłać do procesu sygnał SIGKILL. Komunikat jest zapisywany w dzienniku jądra.
Out of Memory: Killed process [pid] [name].
Jak kontrolować OOM-Killer
W systemie Linux możesz włączyć lub wyłączyć OOM-Killer (chociaż to drugie nie jest zalecane). Aby włączyć lub wyłączyć, użyj parametru vm.oom-kill
. Aby włączyć OOM-Killer w czasie wykonywania, uruchom polecenie sysctl
.
sudo -s sysctl -w vm.oom-kill = 1
Aby wyłączyć OOM-Killer, w tym samym poleceniu podaj wartość 0:
sudo -s sysctl -w vm.oom-kill = 0
Wynik tego polecenia nie zostanie zapisany na zawsze, ale tylko do pierwszego ponownego uruchomienia. Jeśli potrzebujesz większej trwałości, dodaj tę linię do pliku /etc/sysctl.conf
:
echo vm.oom-kill = 1 >>/etc/sysctl.conf
Innym sposobem włączania i wyłączania jest napisanie zmiennej panic_on_oom
. Wartość zawsze można sprawdzić /proc
.
$ cat /proc/sys/vm/panic_on_oom
0
Jeśli ustawisz wartość na 0, to gdy skończy się pamięć, nie będzie paniki jądra.
$ echo 0 > /proc/sys/vm/panic_on_oom
Jeśli ustawisz wartość na 1, gdy skończy się pamięć, nastąpi panika jądra.
echo 1 > /proc/sys/vm/panic_on_oom
OOM-Killer można nie tylko włączać i wyłączać. Powiedzieliśmy już, że Linux może zarezerwować dla procesów więcej pamięci niż jest dostępna, bez jej faktycznego przydzielania, a zachowanie to jest kontrolowane przez parametr jądra Linuksa. Zmienna jest za to odpowiedzialna vm.overcommit_memory
.
Możesz określić dla niego następujące wartości:
0: Jądro samo decyduje, czy zarezerwować zbyt dużo pamięci. Jest to ustawienie domyślne w większości wersji Linuksa.
1: Jądro zawsze rezerwuje dodatkową pamięć. Jest to ryzykowne, ponieważ może zabraknąć pamięci, bo najprawdopodobniej pewnego dnia procesy będą jej potrzebować.
2: jądro nie zarezerwuje więcej pamięci niż określono w parametrze overcommit_ratio
.
Za pomocą tego parametru określa się procent pamięci, która może zostać nadmiernie zarezerwowana. Jeśli nie będzie na to miejsca, pamięć nie zostanie przydzielona, a rezerwacja zostanie odrzucona. Jest to najbezpieczniejsza opcja zalecana dla PostgreSQL. Na OOM-Killer wpływa jeszcze jeden element – możliwość zamiany, która jest kontrolowana przez zmienną cat /proc/sys/vm/swappiness
. Wartości te mówią jądru, jak obsługiwać stronicowanie. Im wyższa wartość, tym mniejsze prawdopodobieństwo, że OOM zakończy proces, ale ze względu na operacje we/wy ma to negatywny wpływ na bazę danych. I odwrotnie – im niższa wartość, tym większe prawdopodobieństwo interwencji OOM-Killer, ale wydajność bazy danych też jest wyższa. Wartość domyślna to 60, ale jeśli cała baza danych mieści się w pamięci, lepiej ustawić wartość na 1.
Wyniki
Nie pozwól, aby „zabójca” w OOM-Killer Cię przestraszył. W tym przypadku zabójca będzie zbawicielem Twojego systemu. „Zabija” najgorsze procesy i chroni system przed awarią. Aby uniknąć konieczności używania OOM-Killer do zakończenia PostgreSQL, ustaw na vm.overcommit_memory
wartość 2. Nie gwarantuje to, że OOM-Killer nie będzie musiał interweniować, ale zmniejszy prawdopodobieństwo wymuszenia zakończenia procesu PostgreSQL.
Źródło: www.habr.com