Blog

Si arritëm deploy-et në zero gabime 502

Çdo herë që deploy-onim backend-in e Mythex, një grusht kërkesash dështonin me 502 Bad Gateway. Jo shumë — por një 502 gjatë deploy-it do të thotë se klikimi i dikujt nuk bëri asgjë, ose një ndërtim që po e shikonte u ndal për një moment. E gjurmuam në dy probleme të ndara: një watchdog vetë-shëruese që luftonte me deploy-et, dhe një boshllëk midis kohës kur një server ndalon së dëgjuari dhe kohës kur load balancer-i ndalon t’i dërgojë trafik. Gjatë tre deploy-eve të njëpasnjëshme të prodhimit pas rregullimeve, numri shkoi nga 10 në 6 dhe në 0.

Konfigurimi

API-ja dhe orkestratori ynë ekzekutohen si kontejnerë në një grup të vogël serverësh pas një Application Load Balancer (ALB) të AWS. Një deploy përditëson një server në një kohë: tërheq kontejnerët e vjetër, nis të rinj dhe kalon te tjetri. Një watchdog në secilin server kontrollon që kontejnerët janë lart dhe rinis çdo gjë që nuk është — ekziston që një proces që u rrëzua në 3 të natës të kthehet pa e zgjuar kush.

Të dyja janë të arsyeshme veç e veç. Së bashku nuk ishin.

Problemi 1: watchdog garonte me deploy-in

Watchdog-u ekzekutohej një herë në minutë dhe "shëronte" pas një health check-u të dështuar. Një deploy me qëllim tërheq shërbimet deri në 150 sekonda — gjatë të cilave një health check duhet të dështojë. Kështu watchdog-u zjarrosej gjatë çdo deploy-i.

Shumicën e herëve e humbiste garën pa dëm. Një herë e fitoi: rishkroi skedarin compose (përshkrimin e kontejnerëve që duhet të ekzekutohen) në mes të një deploy-i, dhe la një server pa asnjë kontejner gateway — ndërsa punë e deploy-it raportoi sukses.

Rregullimet:

  • Një bllokim. Deploy-i tani merr të njëjtën bllokim skedari si skripti i bootstrap-it të serverit, që watchdog-u dhe një deploy të mos mund të ekzekutohen kurrë njëkohësisht.
  • Katër goditje, jo një. Watchdog-u ka nevojë për katër health check-e radhazi të dështuara përpara se të veprojë. Një shërbim që po tërhiqet nuk duket më i vdekur.
  • Një përcaktim. Skedari compose tani ka një burim të vetëm, të publikuar te serverët, në vend të kopjeve që mund të ndahen.
  • Verifiko, mos beso. Punës së deploy-it nuk i mjafton më që një komandë të kthejë sukses. Ajo kontrollon API-n, orkestratorin, gateway-in dhe worker-in e publikimit të çdo serveri përpara se të mund të kalojë.

Problemi 2: serveri u largua përpara trafikut

Problemi i dytë ishte më i heshtur. Kur një deploy tërheq një server, serveri fillon t’i përgjigjet endpoint-it të tij të shëndetit me 503 që load balancer-i ta nxjerrë nga qarkullimi. Yni e bënte këtë për 5 sekonda, pastaj mbyllej.

Por ALB kontrollonte shëndetin vetëm herë pas here, dhe kishte nevojë për disa dështime radhazi përpara se të ndalonte dërgimin te një target — deri rreth 60 sekonda gjithsej. Kështu për rreth 55 sekonda, load balancer-i vazhdonte t’i dërgonte kërkesa reale një serveri që kishte ndalur së dëgjuari. Ato ishin 502-at tona.

Zgjidhja ishte t’i bënim dy afatet të përputhen:

  • Target group tani kontrollon çdo 5 sekonda dhe shënon një target si të pashëndetshëm pas 2 dështimesh — rreth 10 sekonda për ta vënë re.
  • Tërheqja vazhdon t’i shërbejë trafikut real për 15 sekonda pasi fillon të dështojë health check-et, kështu që gjithmonë ka mbivendosje.
  • Këto cilësime jetojnë në skriptin që siguron infrastrukturën, jo në një konsolë që dikush e klikoi një herë.

Mbajtja e numrave që mbështesin njëri-tjetrin

Kohët e tilla varen nga njëra-tjetra. Tërheqja duhet të zgjasë më shumë sesa i duhet balancer-it për ta vënë re; tërheqja plus mbyllja duhet të përfundojë përpara se kontejneri të vritet me forcë. Është e lehtë që dikush të ndryshojë një numër në gjashtë muaj dhe pa e vënë re të rikthejë gabimin.

Kështu i shkruam këto marrëdhënie si teste: tërheqja duhet të jetë më e gjatë se intervali i health check-ut shumëzuar me pragun e dështimit; koha për t’u shënuar sërish i shëndetshëm duhet të mbetet e shkurtër; e gjithë tërheqja duhet të futet brenda periudhës së ndalimit të kontejnerit. Ndrysho një numër pa të tjerët dhe CI dështon. I mutacionuam vetë testet — ndryshuam çdo numër në një vlerë të gabuar dhe kontrolluam që një test ta kapte.

Matja e një deploy-i është e lehtë të gabohet

Matja e parë thoshte se një deploy i pastër ishte rreth 3% i prishur. Nuk ishte. Po numronim çdo përgjigje jo-200, dhe një 503 nga një health endpoint gjatë tërheqjes nuk është dështim — është tërheqja që bën punën e vet, duke i thënë balancer-it të mos zgjedhë atë server ndërsa ai vazhdon të shërbejë kërkesa reale.

Gjithë ajo që ndjen përdoruesi është një 502: kërkesa nuk arriti asgjë. Numërimi vetëm i atyre dha pamjen e vërtetë — 10, pastaj 6, pastaj 0 gjatë tre deploy-eve të prodhimit.

Çfarë nxorëm nga kjo

  • Vetë-shërimi duhet të dijë për ndërprerjet e planifikuara. Një watchdog që nuk mund të dallojë një deploy nga një rrëzim do të përplaset me deploy-in në fund.
  • Tërheqja është një dorëdhënie. Serveri duhet të vazhdojë të shërbejë derisa load balancer-i të jetë vërtetuar që ka ndalur dërgimin e trafikut, dhe ai timing vendoset te balancer-i, jo te serveri.
  • Koduar invariantët si teste. Numrat operacionalë shmangen nga vlerat e tyre. Testet që i lidhin me njëri-tjetrin nuk shmangen.
  • Vendosni çfarë po matni përpara se ta matni. "Gabime" ishte metrika e gabuar; "kërkesa që nuk arritën asgjë" ishte e saktë.

Nëse publikoni një aplikacion në Mythex, asnjë nga kjo nuk është e dukshme për ju — dhe kjo është qëllimi. E lidhur: si qëndron aplikacioni yt i publikuar gjatë ripublikimit.

Mythex · Pricing · Ndërtoni çdo gjë me AI · Shablone faqesh dhe aplikacionesh · Mythex në krahasim · Fjalori i ndërtimit të aplikacioneve me AI · Mjete falas për ndërtimin e aplikacioneve me AI · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk 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 Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)