Skedari i mungueshëm i swap-it që ngriu serverët tanë
Më 24 shtator, një nga serverët tanë të prodhimit pushoi së përgjigjuri. Load balancer-i e shënoi si të pashëndetshëm dhe mjeti ynë i komandave remote nuk mund ta arrinte — por asgjë nuk ishte rrëzuar dhe asnjë proces nuk ishte vrarë për përdorim të tepërt të memories. Serveri po bënte thrashing: pa hapësirë swap dhe me kontejnerë që lejoheshin të përdornin më shumë memorie sesa kishte makina, Linux-i kalonte kohën duke zhvendosur dhe rilexuar skedarët që i duheshin për të ekzekutuar, dhe bënte pothuajse asnjë progres. Shtimi i një skedari swap 2 GB në çdo server e rregulloi. Mësimi më interesant ishte për health check-et.
Si dukej "ngrirja"
- Health check-et e load balancer-it skadonin te ai server.
- Komandat e dërguara përmes AWS Systems Manager qëndronin në "Pending" dhe nuk ekzekutoheshin kurrë.
- Në log-e nuk kishte asnjë kill për mungesë memorie. Asnjë proces nuk vdiq.
Një javë më parë kishim zhvendosur prodhimin te serverë më të vegjël ARM me 2 GB RAM secili. Serveri ynë i staging-ut — akoma më i vogël — kishte ngrirë në të njëjtën mënyrë gjatë shpaketimit të një image kontejneri gjatë një deploy-i.
Pse nuk kishte gabim memorie?
Linux vret një proces vetëm kur me të vërtetë mbaron memorien që mund të rimarrë. Përpara kësaj pike, rimerr memorie nga page cache — kopjet e skedarëve që mban në RAM, duke përfshirë kodin e çdo programi që ekzekutohet.
Te serverët tanë, kufijtë e kombinuar të memories së kontejnerëve shtoheshin në rreth 3.3 GB në një makinë me rreth 1.8 GB të përdorshme. Normalisht nuk arrinin të gjithë kufirin njëkohësisht. Kur e arritën, kerneli vazhdonte të hiqte kodin e programeve nga cache për të bërë vend, dhe pastaj duhej ta rilexonte nga disku pikërisht kur ai kod ekzekutohej përsëri. Ai cikël — thrashing — mund ta bëjë një makinë pothuajse plotësisht të pa përgjigjshme pa mbaruar kurrë teknikisht memorien. Kështu asgjë nuk vritet, dhe asgjë nuk rikuperohet.
Pa swap, kerneli nuk ka ku të vendosë memorinë që është alokuar por përdoret rrallë, kështu që duhet ta marrë nga cache.
Zgjidhja
Skripti i bootstrap-it të serverit tani krijon një skedar swap 2 GB me një swappiness të ulët (10) sa herë që bootohet ose riparohet një server. Swappiness i ulët do të thotë që kerneli ende preferon të mbajë memorinë e punës në RAM, por faqet e prekura rrallë mund të zhvendosen në disk, në vend që të detyrojnë kodin e programit jashtë cache-it. E aplikuam live te të dy serverët e prodhimit dhe te staging-u, dhe pipeline-i i deploy-it ripublikon skriptin e bootstrap-it në çdo deploy prodhimi, që një server i zëvendësuar ta marrë edhe ai.
Pjesa që na shqetësoi më shumë: serveri i pashëndetshëm mbeti
Grupi ynë i serverëve përdorte health check-e EC2 — "a po punon makina?" — jo health check-e të load balancer-it — "a po u përgjigjet kërkesave?". Kështu një server që load balancer-i e kishte braktisur ishte ende i shëndetshëm për grupin. Nuk do të zëvendësohej kurrë. Prodhimi do të ekzekutohej në heshtje në një server të vetëm derisa dikush ta vërejë dhe të rinisë tjetrin.
Kalimi i grupit te health check-et e load balancer-it duket si zgjidhja e dukshme, por nuk është e thjeshtë për ne: gjatë një deploy-i, serverët qëllimisht u përgjigjen endpoint-it të tyre të shëndetit me një gabim, që balancer-i t’i nxjerrë nga qarkullimi (shihni si arritëm deploy-e me zero 502). Një grup që zëvendëson serverët me këtë sinjal do t’i zëvendësonte në mes të çdo deploy-i.
Kështu që për momentin shtuam një hap në listën tonë të kontrollit të deploy-it: pas çdo deploy-i, kontrollojmë shëndetin e çdo target-i në load balancer, jo vetëm nëse punën e deploy-it e kaloi. Nëse komandat te një server qëndrojnë në "Pending", po bën thrashing — rinise; është tashmë jashtë rotacionit.
Çfarë nxorëm nga kjo
- "Nuk po rrëzohet" nuk do të thotë "e shëndetshme". Thrashing-u nuk prodhon gabim, vetëm ngadalësi kaq ekstreme sa makina pushon së përgjigjuri.
- Serverët e vegjël kanë nevojë për swap. Edhe pak, me swappiness të ulët, i jep kernelit ku të vendosë memorien e ftohtë.
- Kufijtë e memories që shtojnë më shumë sesa ka makina janë bast. Ndonjëherë e humbni. Dijeni kur e keni bërë.
- Dijeni cilin health check i beson autoscaling-u juaj. Një health check që pyet vetëm "a është VM-ja e ndezur?" nuk do të zëvendësojë një server që ka pushuar së punuari.