Kun muisti loppuu, OOM Killer tappaa talossa ja puutarhassa
Käyttömuisti, eli RAM, on tietokoneelle elinehto, sillä kaikki tietokoneella ajettavat ohjelmat vaativat käyttömuistia toimiakseen. Käyttömuistiin tallennetaan suorituksen ajaksi paitsi itse suoritettava ohjelma, myös sen käsittelemä data. Tässä kirjoituksessa käsitellään sitä, mitä tapahtuu, jos käyttömuisti loppuu kesken.
Käytännössä kaikki tuottamamme verkkopalvelut toimivat Linux-pohjaisilla palvelimilla. Linuxin ydin vastaa muistin jakamisesta eri prosesseille. Muistivarausten suhteen ydin toimii oletuksena hieman samalla tavalla kuin hotellit tai lentoyhtiöt: prosessit voivat yhteensä pyytää enemmän muistia kuin mitä järjestelmällä on käytettävissä, koska oletuksena on, että prosessit eivät kuitenkaan ihan tuota kaikkea muistia oikeasti käytä. Käyttöjärjestelmä siis mielellään ylibuukkaa muistivarannot ja olettaa, että ei se muisti sieltä lopu, koska osa prosesseista kuitenkin jättää varaamansa muistin käyttämättä.
Pääsääntöisesti tällainen toiminta on OK ja muistia jää hyvin vapaaksi. Toisinaan kuitenkin käy niin, että useampi prosessi oikeasti käyttääkin kaiken varaamansa muistin ja ytimen harjoittama ylibuukkaus ajaa järjestelmän tilanteeseen, jossa muistikapasiteetti yksinkertaisesti loppuu kesken. Tällaisessa tilanteessa muistia on jotenkin pakko saada vapautettua ja silloin vapahtajaksi saapuu OOM Killer.
OOM Killer on valikoiva sarjamurhaaja
OOM Killer (Out of Memory Killer) on prosessi, jonka Linux-ydin käynnistää automaattisesti, kun järjestelmän vapaa muisti on loppumassa. OOM Killerin tehtävänä on lahdata järjestelmästä sopivat ajossa olevat prosessit muistin vapauttamiseksi. Tuo sopivien prosessien valitseminen tapahtuu seuraavien sääntöjen perusteella:
- Prosessi on hyvä kandidaatti tapettavaksi, jos se käyttää (yhdessä lapsiprosesseineen) paljon muistia.
- Prosessi on huono uhrikandidaatti, jos se on tärkeä itse käyttöjärjestelmän toiminnalle.
- Pyritään siihen, että muistipainetta saadaan helpotettua tappamalla mahdollisimman vähän prosesseja – mieluiten vain yksi.
Kun sopiva prosessikandidaatti (tai useampi) on löytynyt, OOM Killer lähettää prosessille SIGKILL
-signaalin. Tuo signaali vastaa komentoriviltä ajettavan kill
-komennon -9
-kahvaa, joka vapaasti suomennettuna on: ”Kuolet, tai itket ja kuolet.”
Miksi OOM Killer murhaa aina juuri ne verkkosivustolle tärkeät prosessit?
Tyypillisen Drupal- tai WordPress-sivuston palvelimella voidaan tarvita ainakin seuraavia palvelinsovelluksia:
- Tietokantapalvelin (esim. MySQL, MariaDB tai PostgreSQL)
- HTTP-palvelin (esim. Apache tai Nginx)
- PHP-ajoympäristö (esim. PHP-FPM)
Tietokantapalvelimen suorituskyvyn kannalta on tärkeää, että se voi pitää suuria määriä dataa käyttömuistissa. Toisaalta taas sovelluksen tekemien tietokantakyselyiden perusteella muodostuvat väliaikaistaulut ja tulosjoukot voivat kasvattaa tietokantapalvelimen muistitarvetta hetkellisesti varsin paljon. Tietokantapalvelin todennäköisesti siis olisi erinomainen uhri OOM Killerille.
PHP-prosessit voivat myös viedä valtavia määriä muistia. Etenkin Drupalin kanssa kannattaa varmistaa, että PHP:n muistikatto on nostettu riittävän korkealle (gigatavu tai pari on vielä ihan normaalia) ja että palvelimelta löytyy riittävästi muistia useamman muistisyöpön prosessin samanaikaiseen ajamiseen. Niinpä myös PHP-prosessit voivat usein olla OOM Killerin tähtäimessä.
Verkkosivuston toteuttavat prosessit siis ovat OOM Killerille usein erittäin hyviä kohteita. Pitää kuitenkin ottaa huomioon tilanne, jossa OOM Killer lähtee murharetkelleen: peli on jo menetetty. Kun muistipaine käy niin korkeaksi, että OOM Killeriä tarvitaan, on kyse enää siitä, pysyykö käyttöjärjestelmä ollenkaan pystyssä vai meneekö se kokonaan nurin. Verkkosivuston toiminnan uhraaminen tässä tilanteessa on ihan OK, kun vaihtoehtona on, että palvelin kaatuu kokonaan. Normaalin toiminnan jatkaminen ei tällöin yksinkertaisesti onnistu.
OOM Killeriin voi vaikuttaa
Kuten yleensä kaikkea muutakin Linuxissa, myös OOM Killerin toimintaa voi konfiguroida mieleisekseen. sysctl:llä on mahdollista vaikuttaa koko järjestelmän toimintaan ja lisäksi säätöjä voidaan tehdä prosessikohtaisesti.
Joissakin tapauksissa voi olla järkevää, että palvelin käynnistetään uudelleen, kun muisti loppuu. Tämä ei ole yleensä ainakaan web-palvelinkäytössä toivottua, mutta saattaa olla hyvä vaihtoehto silloin, kun palvelimen olemassaolon tarkoitus on ajaa yhtä tiettyä kriittistä sovellusta. Tämä onnistuu asettamalla sysctl
:llä asetus vm.panic_on_oom
arvoon 1 ja määrittämällä kernel.panic
-asetukselle sekuntimäärä, jonka jälkeen palvelin uudelleenkäynnistetään, kun käyttöjärjestelmäydin on panikoinut. Eli esim. näin:
$ sysctl vm.panic_on_oom=1
$ sysctl kernel.panic=15
$ echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
$ echo "kernel.panic=15" >> /etc/sysctl.conf
Esimerkissä ensin asetetaan käyttöjärjestelmäydin panikoimaan, kun muisti loppuu, ja sen jälkeen tekemään uudelleenkäynnistys, kun ydin on ehtinyt olla 15 sekuntia paniikissa. Kaksi viimeistä riviä tallentavat asetukset sysctl.conf
-asetustiedostoon, jotta ne tulevat voimaan uudelleenkäynnistyksen yhteydessä automaattisesti.
Tämän lisäksi voidaan vaikuttaa siihen, kuinka helposti yksittäiset ajossa olevat prosessit joutuvat OOM Killerin tappolistalle. Tämä onnistuu asettamalla prosessikohtainen oom_adj
-asetus esim. seuraavasti:
$ echo -15 > /proc/1234/oom_adj
Esimerkissä ID:llä 1234 olevan prosessin oom_adj
-asetukselle annetaan arvo -15, joka tarkoittaa, että OOM Killer jättää ko. prosessin erittäin suurella todennäköisyydellä rauhaan. oom_adj
-asetuksen arvot voivat vaihdella välillä -16–15 ja prosessin eloonjäännin voi varmistaa antamalla asetukselle arvon -17.
Sen sijaan, että koitetaan väkisin pitää muistisyöppöjä prosesseja elossa, on ehkä järkevämpää pyrkiä tarjoamaan OOM Killerille sopivia uhreja – esimerkiksi PHP-prosesseja. Tämä onnistuu asettamalla näiden prosessien oom_adj
-asetus lähelle maksimiarvoa (15).
On myös mahdollista – joskin usein himpun verran tyhmää – vaikuttaa siihen, miten järjestelmän muistiylivaraus toimii. Järjestelmä voi tämän suhteen toimia kolmessa vaihtoehtoisessa moodissa:
0
: Heuristinen ylivaraus, eli käytäntö, jossa selkeät ylivaraustapaukset estetään. Ydin siis ei salli varata sellaisia muistialueita, jotka oletettavasti menisivät liian paljon yli käytettävissä olevasta muistiavaruudesta. Tässä moodissa ydin tekee tavallaan valistuneen arvauksen muistitilanteesta, ei tarkkaa laskelmaa. Tämä on yleensä järjestelmän oletusasetus.1
: Kaikki varaukset sallitaan aina riippumatta siitä, paljonko muistia oikeasti on käytettävissä. Tämä vaikuttaa hasardilta, mutta on yllättäen järkevä toimintamalli joissakin hyvin tarkkaan rajatuissa tapauksissa, kuten Redis-palvelimilla.2
: Oikea muistitilanne tarkistetaan aina ennen varausta ja ylivarausta sallitaan vainovercommit_ratio
-asetuksen määrittämän osan verran (plus tietysti swap, mutta se ei ole tässä relevantti).overcommit_ratio
-asetuksella voidaan määrittää, kuinka monta prosenttia oikean muistikapasiteetin yli muistia voidaan varata. Tämä moodi vastaa toiminnaltaan0
-moodia, mutta sillä erotuksella, että tarkka, todellinen muistitilanne tarkistetaan aina ennen muistin varaamista. Tällä on vaikutusta järjestelmän suorituskykyyn.
Lähtökohtaisesti oletusmoodi on järkevä vaihtoehto, eikä sitä juurikaan kannata lähteä vaihtamaan ilman erittäin painavia perusteita. Tässä kuitenkin esimerkki siitä, miten ylivarausmoodia voidaan vaihtaa sysctl:llä:
$ sysctl vm.overcommit_memory=2
$ echo "vm.overcommit_memory=2" >> /etc/sysctl.conf
Kuka pelkää OOM Killeriä?
Tähän kuuluu nyt vastata: ”En minä ainakaan!” OOM Killer nimittäin on ystävä, joka pelastaa pinteestä, kun hommat meinaavat karata lapasesta. Käyttömuistin loppuminen on palvelimen toiminnan kannalta kriittinen tilanne, eikä toimintaa tuolloin enää voida jatkaa normaalisti. On ihan OK, että OOM Killer tappaa palvelimelta prosesseja, mikäli sillä voidaan edesauttaa palvelun palauttamista normaaliin tilaan. Oikein konfiguroituna Linuxin ytimen muistivaraus toimii hyvin, ja usein oletusasetukset ovat järkevät. On kuitenkin hyvä tunnistaa sellaiset tilanteet, joissa muistin ylivarausta ja OOM Killerin toimintaa kannattaa muuttaa johonkin suuntaan – verkkopalvelut kun ovat erilaisia ja kaikilla on omat, uniikit tarpeensa ja rajoituksensa.