Trūkstošais swap fails, kas iesaldēja mūsu serverus
- septembrī viens no mūsu ražošanas serveriem pārstāja atbildēt. Slodzes sadalītājs to atzīmēja kā neveselīgu, un mūsu attālās komandas rīks nevarēja tam piekļūt, bet nekas nebija nokritis un neviens process nebija nogalināts par pārāk lielu atmiņas izmantošanu. Serveris bija pārslogots: bez swap vietas un ar konteineriem, kam atļauts izmantot vairāk atmiņas, nekā mašīnā bija, Linux savu laiku pavadīja, izmetot un atkārtoti lasot failus, kas tam vajadzīgi darbam, un gandrīz neko nepaveica. 2 GB swap fails katrā serverī to novērsa. Interesantāka mācība bija par veselības pārbaudēm.
Kā izskatījās „iestrēdzis“
- Slodzes sadalītāja veselības pārbaudes šajā serverī noilga.
- Komandas, kas nosūtītas caur AWS Systems Manager, palika stāvoklī „Pending“ un nekad neizpildījās.
- Žurnālos nebija nogalināšanas par atmiņas pārpildi. Neviens process nebija miris.
Nedēļu iepriekš mēs pārcēlām ražošanu uz mazākiem ARM serveriem ar 2 GB RAM katrā. Mūsu stagings serveris, vēl mazāks, tāpat iesala, kamēr atsaiņoja konteinera attēlu izvietošanas laikā.
Kāpēc nebija atmiņas kļūdas?
Linux nogalina procesu tikai tad, kad tiešām beidzas atmiņa, ko var atgūt. Pirms tam tas atgūst atmiņu no lapu kešatmiņas, failu kopijām, ko tas tur RAM, ieskaitot katras darbojošās programmas kodu.
Mūsu serveros konteineru kopējie atmiņas ierobežojumi sastādīja apmēram 3,3 GB mašīnā ar apmēram 1,8 GB izmantojamu. Parasti tie visi nelieto savu ierobežojumu vienlaikus. Kad tā notika, kodols turpināja izmest programmas kodu no kešatmiņas, lai atbrīvotu vietu, un pēc tam to nolasīja atpakaļ no diska, tiklīdz šis kods atkal darbojās. Šis cikls, pārslodze, var padarīt mašīnu gandrīz pilnīgi neatsaucīgu, kamēr tā tehniski nekad nebeidz atmiņu. Tātad nekas netiek nogalināts, un nekas neatgūstas.
Bez swap kodolam nav kur likt atmiņu, kas ir piešķirta, bet reti izmantota, tāpēc tam tā jāņem no kešatmiņas.
Labojums
Servera sagatavošanas skripts tagad izveido 2 GB swap failu ar zemu swappiness iestatījumu (10) katru reizi, kad serveris startē vai tiek labots. Zems swappiness nozīmē, ka kodols joprojām dod priekšroku darba atmiņai RAM, bet reti pieskarīgās lapas var pāriet uz disku, nevis piespiest programmas kodu ārā no kešatmiņas. Piemērojām to tiešraidē abiem ražošanas serveriem un stagingam, un izvietošanas cauruļvads katrā ražošanas izvietošanā publicē sagatavošanas skriptu no jauna, lai arī nomainīts serveris to saņemtu.
Vairāk uztrauca: nepareizais serveris palika
Mūsu serveru grupa izmantoja EC2 veselības pārbaudes („vai mašīna darbojas?“), nevis slodzes sadalītāja veselības pārbaudes („vai tas atbild uz pieprasījumiem?“). Tātad serveris, no kura slodzes sadalītājs bija atteicies, grupai joprojām bija vesels. Tas nekad netiktu aizstāts. Ražošana klusi darbotos uz viena servera, līdz kāds to pamanītu un restartētu otru.
Pārslēgt grupu uz slodzes sadalītāja veselības pārbaudēm šķiet acīmredzams labojums, bet mums tas nav vienkārši: izvietošanas laikā serveri tīši atbild uz savu veselības galapunktu ar kļūdu, lai sadalītājs tos izvadītu (skat. kā panācām izvietošanu bez 502 kļūdām). Grupa, kas aizstātu serverus pēc šī signāla, aizstātu tos katras izvietošanas vidū.
Tāpēc pagaidām pievienojām soli mūsu izvietošanas kontrolsarakstam: pēc katras izvietošanas pārbaudi katra mērķa veselību slodzes sadalītājā, nevis tikai to, vai izvietošanas darbs izturējās. Ja komandas uz serveri paliek „Pending“, tas pārslogojas; restartē to, tas jau ir ārpus rotācijas.
Ko no tā guvām
- „Nenokrīt“ nenozīmē „vesels“. Pārslodze nerada kļūdu, tikai tik ekstremālu lēnumu, ka mašīna pārstāj atbildēt.
- Maziem serveriem vajag swap. Pat neliels, ar zemu swappiness, dod kodolam vietu, kur likt vēsu atmiņu.
- Atmiņas ierobežojumi, kas kopā pārsniedz mašīnu, ir derība. Dažreiz to zaudē. Zini, kad to esi izdarījis.
- Zini, kurai veselības pārbaudei tavs autoskalēšanas mehānisms uzticas. Veselības pārbaude, kas jautā tikai „vai VM ir ieslēgta?“, neaizstās serveri, kas pārstājis darboties.