Blog

Sådan fik vi udrulninger ned til nul 502-fejl

Hver gang vi udrullede Mythex' backend, fejlede et håndfuld forespørgsler med 502 Bad Gateway. Ikke mange — men en 502 under en udrulning betyder, at nogens klik ikke gjorde noget, eller at et build, de fulgte med i, gik i stå et øjeblik. Vi sporede det til to adskilte problemer: en selvhelende watchdog, der kæmpede mod vores udrulninger, og et hul mellem, hvornår en server holdt op med at lytte, og hvornår load balanceren holdt op med at sende den trafik. På tværs af tre på hinanden følgende produktionsudrulninger efter rettelserne gik antallet fra 10 til 6 til 0.

Opsætningen

Vores API og orkestrator kører som containere på en lille gruppe servere bag en AWS Application Load Balancer (ALB). En udrulning opdaterer én server ad gangen: den dræner de gamle containere, starter nye og går videre. En watchdog på hver server tjekker, at containerne kører, og genstarter alt, der ikke gør — den findes, så en proces, der går ned kl. 3 om natten, kommer tilbage uden at nogen skal vækkes.

Begge dele er fornuftige hver for sig. Sammen var de ikke det.

Problem 1: watchdog'en kappedes med udrulningen

Watchdog'en kørte én gang i minuttet og "helede" ved ét fejlet health check. En udrulning dræner bevidst services i op til 150 sekunder — og i den periode skal et health check netop fejle. Så watchdog'en slog til under hver eneste udrulning.

De fleste gange tabte den væddemålet harmløst. En gang vandt den: den omskrev compose-filen (beskrivelsen af hvilke containere der skal køre) midt i en udrulning og efterlod en server uden nogen gateway-container overhovedet — mens udrulningsjobbet meldte succes.

Rettelserne:

  • Ét lås. Udrulningen tager nu samme filelås som serverens bootstrap-script, så watchdog'en og en udrulning aldrig kan køre samtidig.
  • Fire strikes, ikke én. Watchdog'en kræver fire fejlede checks i træk, før den handler. En dræning ser ikke længere ud som død.
  • Én definition. Compose-filen har nu præcis én kilde, udgivet til serverne, i stedet for kopier der kunne drive fra hinanden.
  • Verificér, stol ikke på det. Udrulningsjobbet lykkes ikke længere, fordi en kommando returnerede. Det tjekker hver servers API, orkestrator, gateway og publiceringsworker, før det kan lykkes.

Problem 2: serveren gik før trafikken gjorde

Det andet problem var mere stille. Når en udrulning dræner en server, begynder serveren at svare sit health-endpoint med 503, så load balanceren tager den ud af rotation. Vores gjorde det i 5 sekunder og lukkede så ned.

Men ALB'en tjekkede helbred kun med jævne mellemrum og krævede flere fejlede checks i træk, før den holdt op med at route til et mål — op til omkring 60 sekunder fra start til slut. Så i cirka 55 sekunder blev der ved med at sendes rigtige forespørgsler til en server, der allerede var holdt op med at lytte. Det var vores 502'er.

Rettelsen var at få de to tidslinjer til at stemme overens:

  • Target group'en tjekker nu hvert 5. sekund og markerer et mål som usundt efter 2 fejl — omkring 10 sekunder om at opdage det.
  • Dræningen fortsætter med at servere rigtig trafik i 15 sekunder, efter den begynder at fejle health checks, så der altid er overlap.
  • Disse indstillinger ligger i scriptet, der provisionerer infrastrukturen, ikke i en konsol, nogen klikkede sig frem til engang.

At få tallene til at holde hinanden i ave

Timeouts som disse afhænger af hinanden. Dræningen skal vare længere end den tid, balanceren behøver for at opdage det; dræning plus nedlukning skal være færdig, før containeren tvangsdrabes. Det er let, at nogen ændrer ét tal om seks måneder og stille og roligt genindfører fejlen.

Så vi skrev disse sammenhænge ned som tests: dræningen skal være længere end health-check-intervallet gange fejltærsklen; tiden til at blive markeret sund igen skal forblive kort; hele dræningen skal kunne være inden for containerens stop-grace-periode. Ændrer du ét tal uden de andre, fejler CI. Vi mutationstestede selve testene — ændrede hvert tal til en forkert værdi og kontrollerede, at en test fangede det.

Måling af en udrulning er let at tage fejl af

Vores første måling sagde, at en ren udrulning var cirka 3 % ødelagt. Det var den ikke. Vi talte hvert ikke-200-svar, og et 503 fra et health-endpoint under en dræning er ikke en fejl — det er dræningen, der gør sit arbejde, og fortæller balanceren ikke at vælge serveren, mens den stadig servicerer rigtige forespørgsler.

Det brugerne mærker, er en 502: forespørgslen nåede ingenting. At tælle kun dem gav det rigtige billede — 10, derefter 6, derefter 0 på tværs af tre produktionsudrulninger.

Det vi tog med

  • Selvhealing skal vide om planlagt nedetid. En watchdog, der ikke kan skelne en udrulning fra et nedbrud, vil før eller siden kæmpe mod udrulningen.
  • Dræning er et håndtryk. Serveren skal blive ved med at servere, indtil load balanceren beviseligt har holdt op med at sende trafik, og den timing sættes på balanceren, ikke på serveren.
  • Kod invarianter som tests. Driftstal driver fra hinanden. Tests, der relaterer dem til hinanden, gør det ikke.
  • Beslut, hvad du måler, før du måler. "Fejl" var den forkerte metrik; "forespørgsler der nåede ingenting" var den rigtige.

Hvis du publicerer en app på Mythex, er intet af dette synligt for dig — og det er pointen. Relateret: hvordan din publicerede app forbliver oppe, mens du udruller den igen.

Mythex · Pricing · Byg hvad som helst med AI · Skabeloner til websites og apps · Mythex sammenlignet · Ordliste for app-bygning med AI · Gratis værktøjer til app-bygning med AI · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)