Podesimo Out-Of-Memory Killer u Linuxu za PostgreSQL

Podesimo Out-Of-Memory Killer u Linuxu za PostgreSQL

Kada Linux server baze podataka neočekivano prestane raditi, potrebno je pronaći uzrok. Uzroka može biti nekoliko. Na primjer, SIGSEGV — greška zbog buga u backend serveru. No, to je rijetkost. Najčešće jednostavno ponestane prostora na disku ili memorije. Ako je prostor na disku ispunjen, jedini izlaz je osloboditi prostor i ponovo pokrenuti bazu podataka.

Killer zbog nedostatka memorije

Kada kod poslužitelja ili procesa ponestane memorije, Linux nudi 2 načina rješavanja: obrušiti cijeli sustav ili prekinuti proces (aplikaciju) koja koristi memoriju. Naravno, bolje je prekinuti proces i spasiti operacijski sustav od katastrofalnog završetka. U dvije rečenice, Out-Of-Memory Killer je proces koji prekida aplikaciju kako bi spasio jezgru od pada. On žrtvuje aplikaciju kako bi očuvao rad operacijskog sustava. Prvo ćemo razgovarati o tome kako OOM funkcionira i kako ga kontrolirati, a zatim ćemo vidjeti kako OOM Killer odlučuje koju aplikaciju prekinuti.

Jedan od glavnih zadataka Linuxa je dodjeljivanje memorije procesima kada je zatraže. Obično proces ili aplikacija traže memoriju od OS-a, a sami je ne koriste u potpunosti. Ako OS dodijeli memoriju svima koji je traže, ali ne planiraju je koristiti, vrlo brzo će ponestati memorije, a sustav će se srušiti. Da bi to izbjegli, OS rezervira memoriju za proces, ali je zapravo ne dodjeljuje. Memorija se dodjeljuje samo kada proces stvarno planira koristiti. Dogodi se da OS nema slobodne memorije, ali zapravo rezervira memoriju za proces, a kada mu zatreba, OS je dodijeli ako može. Nedostatak je što ponekad OS rezervira memoriju, ali u ključnom trenutku nema slobodne memorije, što dovodi do pada sustava. OOM igra važnu ulogu u ovom scenariju i prekida procese kako bi zaštitio jezgru od panike. Kada se prisilno prekine proces PostgreSQL, u dnevniku se pojavljuje poruka:

Nema dovoljno memorije: Ubio proces 12345 (postgres).

Ako u sustavu nedostaje memorije i nije moguće osloboditi je, poziva se funkcija out_of_memory. U ovoj fazi nje preostaje ništa drugo nego završiti jedan ili više procesa. OOM-killer mora odmah prekinuti proces ili se može čekati? Očito je da kada se poziva out_of_memory, to je povezano s čekanjem na I/O operaciju ili stranicom koja se preselila na disk. Stoga OOM-killer prvo mora izvršiti provjere i na temelju njih odlučiti koji proces treba prekinuti. Ako svi sljedeći uvjeti budu ispunjeni, OOM će prekinuti proces.

Odabir procesa

Kada ponestane memorije, poziva se funkcija out_of_memory(). Ima funkciju select_bad_process(), koja dobiva ocjenu iz funkcije badness(). Najslabiji proces bit će zaustavljen. Funkcija badness() odabire proces prema određenim pravilima.

  1. Jezgru je potrebna neka minimalna memorija za sebe.
  2. Potrebno je osloboditi mnogo memorije.
  3. Nije potrebno prekidati procese koji koriste malo memorije.
  4. Potrebno je prekinuti minimalno procese.
  5. Složeniji algoritmi koji povećavaju šanse za prekid onih procesa koje korisnik sam želi prekinuti.

Nakon što izvrši sve te provjere, OOM proučava ocjenu (oom_score). OOM dodjeljuje oom_score svakom procesu, a zatim množi tu vrijednost s količinom memorije. Procesi s većim vrijednostima imaju veće šanse postati žrtve OOM Killer-a. Procesi povezani s privilegiranim korisnikom imaju nižu ocjenu i manje šanse za prisilno završavanje.

postgres=# SELECT pg_backend_pid();
pg_backend_pid 
----------------
    3813
(1 row)

Identifikator procesa Postgres je 3813, pa u drugoj ljusci možete dobiti ocjenu koristeći ovu datoteku jezgre oom_score:

vagrant@vagrant:~$ sudo cat /proc/3813/oom_score
2

Ako ne želite da OOM-Killer prekine proces, postoji još jedan parametar jezgre: oom_score_adj. Dodajte veliku negativnu vrijednost kako biste smanjili šanse za završavanje procesa koji vam je važan.

sudo echo -100 > /proc/3813/oom_score_adj

Da biste postavili vrijednost oom_score_adj, postavite OOMScoreAdjust u bloku usluge:

[Service]
OOMScoreAdjust=-1000

Ili upotrijebite oomprotect u naredbi rcctl.

rcctl set servicename oomprotect -1000

Prisilno završavanje procesa

Kada jedan ili više procesa već bude odabrano, OOM-Killer poziva funkciju oom_kill_task(). Ova funkcija šalje procesu signal za završetak. U slučaju nedostatka memorije oom_kill() poziva ovu funkciju da pošalje procesu signal SIGKILL. Poruka se bilježi u jezgreni dnevnik.

Out of Memory: Ubio proces [pid] [name].

Kako kontrolirati OOM-Killer

U Linuxu možete uključiti i isključiti OOM-Killer (iako se drugo ne preporučuje). Za uključivanje i isključivanje koristite parametar vm.oom-kill. Da biste uključili OOM-Killer u radnom okruženju, izvršite naredbu sysctl.

sudo -s sysctl -w vm.oom-kill=1

Da biste isključili OOM-Killer, navedite 0 u ovoj istoj naredbi:

sudo -s sysctl -w vm.oom-kill=0

Rezultat ove naredbe neće biti trajno sačuvan, već samo do prvog restarta. Ako je potrebna veća trajnost, dodajte ovu liniju u datoteku /etc/sysctl.conf:

echo vm.oom-kill=1 >> /etc/sysctl.conf

Još jedan način uključivanja i isključivanja je da napišete varijablu panic_on_oom. Vrijednost se uvijek može provjeriti u /proc.

$ cat /proc/sys/vm/panic_on_oom
0

Ako postavite 0, kada dođe do iscrpljivanja memorije, kernel panic se neće dogoditi.

$ echo 0 > /proc/sys/vm/panic_on_oom

Ako postavite 1, kada dođe do iscrpljivanja memorije, doći će do kernel panica.

echo 1 > /proc/sys/vm/panic_on_oom

OOM-Killer ne samo da se može uključiti i isključiti. Već smo spomenuli da Linux može rezervirati više memorije za procese nego što je ima, ali je ne dodjeljuje u stvarnosti, a to ponašanje upravlja parametrom jezgre Linuxa. Za to je odgovorna varijabla vm.overcommit_memory.

Možete navesti sljedeće vrijednosti za nju:

0: jezgra sama odlučuje treba li rezervirati previše memorije. Ovo je zadana vrijednost u većini verzija Linuxa.
1: jezgra će uvijek rezervirati dodatnu memoriju. To je rizično, jer se memorija može iscrpiti, jer će vjerojatno jednom procesi zatražiti ono što im pripada.
2: jezgra neće rezervirati više memorije nego što je navedeno u parametru overcommit_ratio.

U ovom parametru navodite postotak memorije za koji je dopušteno prekomjerno rezerviranje. Ako nema mjesta za to, memorija se ne dodjeljuje, a rezervacija će biti odbijena. Ovo je najsigurnija opcija, preporučena za PostgreSQL. Na OOM-Killer također utječe još jedan element — mogućnost swapanja, kojom upravlja varijabla cat /proc/sys/vm/swappiness. Ove vrijednosti upućuju jezgru kako da obrađuje swapanje stranica. Što je veća vrijednost, manja je vjerojatnost da će OOM završiti proces, ali to negativno utječe na bazu podataka zbog operacija ulaz/izlaz. I obrnuto — što je manja vrijednost, veća je vjerojatnost intervencije OOM-Killer-a, ali je i produktivnost baze podataka veća. Zadana vrijednost je 60, ali ako se cijela baza podataka može smjestiti u memoriju, bolje je postaviti vrijednost 1.

Zaključci

Ne dajte da vas zastraši «ubica» u OOM-Killeru. U ovom slučaju, ubica će biti spasilac vašeg sistema. On „ubija“ najproblematičnije procese i štiti sistem od nesretnog gašenja. Da ne biste morali koristiti OOM-Killer za zatvaranje PostgreSQL-a, postavite vm.overcommit_memory vrijednost 2. To ne garantira da OOM-Killer neće morati intervenisati, ali će smanjiti vjerojatnost prisilnog zatvaranja procesa PostgreSQL-a.

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster