A hiányzó swap-fájl, amely lefagyasztotta a szervereinket
Szeptember 24-én az egyik éles szerverünk nem válaszolt többé. A terheléselosztó egészségtelennek jelölte, és a távoli parancseszközünk sem tudott hozzáférni — de semmi nem omlott össze, és egyetlen folyamat sem lett memóriahasználat miatt megölve. A szerver csörtetett (thrashing): mivel nem volt swap-terület, és a konténerek több memóriát használhattak, mint amennyi a gépen volt, a Linux azzal töltötte az idejét, hogy kiürítette és újraolvasta a futáshoz szükséges fájlokat, és szinte semmi haladás nem történt. Egy 2 GB-os swap-fájl minden szerveren megoldotta. Az érdekesebb tanulság az egészségügyi ellenőrzésekről szólt.
Hogyan nézett ki a „lefagyás”
- A terheléselosztó egészségügyi ellenőrzései időtúllépésbe futottak azon a szerveren.
- Az AWS Systems Manageren keresztül küldött parancsok „Pending” állapotban ragadtak, és soha nem futottak le.
- A logokban nem volt memória-hiányos leállás. Egyetlen folyamat sem halt meg.
Egy héttel korábban átköltöztettük az éles rendszert kisebb ARM-szerverekre, mindegyik 2 GB RAM-mal. A stagingszerverünk — ami még kisebb — ugyanígy lefagyott, amikor egy deploy során egy konténerképet csomagolt ki.
Miért nincs memóriahiba?
A Linux csak akkor öl meg egy folyamatot, ha valóban elfogy a visszanyerhető memória. Addig a pont előtt a lap-gyorsítótárból (page cache) nyer vissza memóriát — a fájlok RAM-beli másolataiból, beleértve minden futó program kódját.
A szervereinken a konténerek együttes memórialimitjei nagyjából 3,3 GB-ot tettek ki egy körülbelül 1,8 GB használható memóriájú gépen. Normál esetben nem használják ki egyszerre a limitjüket. Amikor mégis, a kernel folyamatosan kiürítette a program-kódot a gyorsítótárból, majd a pillanatban, amint az a kód újra futott, vissza kellett olvasnia a lemezről. Ez a ciklus — a csörtetés — szinte teljesen válaszképtelenné teheti a gépet úgy, hogy technikailag soha nem fogy el a memória. Így nincs leölt folyamat, és nincs felépülés sem.
Swap nélkül a kernelnek nincs hova tennie a lefoglalt, de ritkán használt memóriát, ezért a gyorsítótárból kell elvennie.
A javítás
A szerver-bootstrap szkript most minden indításnál vagy javításnál létrehoz egy 2 GB-os swap-fájlt alacsony swappiness-értékkel (10). Az alacsony swappiness azt jelenti, hogy a kernel továbbra is a RAM-ban tartja előnyben a működő memóriát, de a ritkán használt lapok lemezre kerülhetnek, ahelyett hogy a program-kódot kényszerítenék ki a gyorsítótárból. Élesben mindkét éles szerveren és a stagingen is alkalmaztuk, a deploy-folyamat pedig minden éles deploynál újra közzéteszi a bootstrap szkriptet, így a cserélt szerver is megkapja.
Ami jobban aggasztott: a nem egészséges szerver bent maradt
Az szerver-csoportunk EC2 egészségügyi ellenőrzéseket használt — „fut a gép?” — nem terheléselosztó egészségügyi ellenőrzéseket — „válaszol a gép a kérésekre?”. Így a szerver, amelyről a terheléselosztó már lemondott, a csoport szempontjából még egészséges volt. Soha nem cserélték volna le. Az éles rendszer csendben egyetlen szerveren futott volna, amíg valaki észre nem veszi és nem indítja újra a másikat.
A csoport átállítása terheléselosztó-ellenőrzésekre kézenfekvő megoldásnak tűnik, de nálunk nem egyszerű: deploy közben a szerverek szándékosan hibát adnak az egészségügyi végpontjukon, hogy a terheléselosztó kivonja őket a forgalomból (lásd: hogyan jutottunk nulla 502-hibához deployoknál). Egy olyan csoport, amely ezen a jelzésen cserélne szervert, minden deploy közepén cserélne.
Egyelőre ezért egy lépést adtunk a deploy-ellenőrzőlistánkhoz: minden deploy után ellenőrizzük minden cél egészségét a terheléselosztón, nem csak azt, hogy a deploy-feladat sikeres volt-e. Ha egy szerverhez küldött parancsok „Pending” állapotban ragadnak, az csörtetés — indítsd újra; már úgyis kikerült a forgalomból.
Amit ebből tanultunk
- A „nem omlik össze” nem egyenlő az „egészséges”-sel. A csörtetés nem ad hibaüzenetet, csak olyan extrém lassúságot, hogy a gép megszűnik válaszolni.
- A kis szervereknek kell swap. Akár csak egy kicsi, alacsony swappiness-szel — ez ad a kernelnek helyet a hideg memóriának.
- Ha a memórialimitek összeadva többet adnak ki, mint a gép, az egy fogadás. Néha elveszíted. Tudd, mikor fogadtál.
- Tudd, melyik egészségügyi ellenőrzésben bízik az automatikus skálázásod. Az az egészségügyi ellenőrzés, amely csak azt kérdezi, „be van-e kapcsolva a VM?”, nem cseréli le a szervert, amely már nem működik.