Blog

Si një chat i rëndë mund ta rrëzonte API-n tonë

Më 28 shtator, rreth 17 minuta pas një publikimi, të dy serverat tanë API në prodhim mbaruan memorien në të njëjtin moment, u rinisën, dhe për rreth pesë minuta load balancer-i nuk kishte asnjë server të shëndetshëm ku t’i dërgonte trafikun. Rregullimi ynë i parë i dha API-t memorie dyfish. Shkaku i vërtetë u gjet më vonë atë ditë: hapja e një chat-i të caktuar i kërkonte API-t të ngarkonte 53 MB mesazhe në një kërkesë të vetme. Historiku i chat-it tani ngarkohet në faqe të kufizuara sipas madhësisë, jo vetëm numrit, dhe ai chat hapet me një faqe të parë 5 MB në vend se të rrëzohet.

Çfarë u prish

API-ja jonë punon si kontejner në secilin nga dy serverat, pas një load balancer-i. Çdo kontejner kishte një kufi memorie prej 384 MiB. Në gjendje pushimi përdor 130–140 MiB, kështu që kufiri dukej si shumë hapësirë.

Të dy kontejnerët arritën kufirin njëkohësisht dhe u rrëzuan me mesazhin “JavaScript heap out of memory”. Heap-i është memoria që përdor një proces Node.js për objektet me të cilat punon. Meqenëse të dy serverat dështuan njëkohësisht, nuk kishte ku t’i drejtoheshin kërkesat. Kjo është forma më e keqe e shkatërrimit për një konfigurim me dy servera: redundanca ndihmon vetëm kur dështimet nuk ndodhin në të njëjtën kohë.

Rregullimi i parë: më shumë vend

Kohëzgjatja tregonte drejt publikimit. Pas një release-i, turnet e agjentit që u ndërprenë nga publikimi rifillojnë dhe ruajnë përsëri transkriptet e tyre, dhe ai hap punë dukej si burimi i qartë i një rritjeje të memories.

Kështu që ndryshimi i parë ngriti kufirin e API-t nga 384 MiB në 768 MiB. E aplikuam drejtpërdrejt në të dy serverat po atë ditë, dhe e commit-uam në konfigurimin e deploy-it, që deploy-i i radhës të mos e kthejë heshtas në 384. Një rregullim i bërë me dorë në një server që deploy-i i radhës e zhbën është një mënyrë e zakonshme për të rikthyer të njëjtën ndërprerje.

Më shumë memorie ishte një marzh i arsyeshëm sigurie. Por nuk ishte një shpjegim.

Shkaku i vërtetë: një kërkesë, 71 MB

Më vonë atë ditë riprodhuam rrëzimin në një kopje të një chat-i, duke përdorur kufirin e vjetër të memories të prodhimit. Kopja e rrëzoi API-n vetë, pa asnjë deploy të përfshirë.

Kur hap një projekt, aplikacioni web i kërkon API-t historikun e chat-it. Endpoint-i kthente 30 mesazhet e fundit, të plota. Për shumicën e chat-eve, 30 mesazhe janë pak. Për këtë, 30 mesazhet e fundit ishin 53 MB në bazën e të dhënave dhe një përgjigje 71 MB. Disa nga përgjigjet e agjentit ishin 4–10 MB secila, kryesisht transkriptet e nën-agjentëve: agjentët ndihmës që agjenti kryesor i nis për të punuar paralelisht në një pjesë të detyrës, punën e plotë të të cilëve e ruajmë bashkë me përgjigjen.

Ndërtimi i asaj përgjigje të vetme kërkonte më shumë heap sesa kishte API-ja. Dhe çdo hapje ose rifreskim i atij projekti e dërgonte përsëri kërkesën. Një chat i vetëm mund të rrëzonte çdo server në të cilin binte, dhe meqenëse faqja mund të rifreskohej, mund të arrinte të dy serverat.

“30 mesazhe” nuk kishte qenë kurrë një kufi i vërtetë për madhësinë. Ishte një kufi për numrin që rastësisht ishte i vogël për chat-et normale.

Rregullimi: faqe të kufizuara sipas madhësisë dhe numrit

Një faqe historiku tani ka 30 mesazhe ose rreth 4 MB të tyre, cilado të vijë e para.

Funksionon në dy hapa:

  1. Kërko fillimisht madhësitë. API-ja i kërkon bazës së të dhënave ID-të dhe madhësitë e ruajtura të mesazheve më të fundit, pa përmbajtjet e tyre. Ajo kërkesë është e lirë pavarësisht sa të mëdha janë mesazhet.
  2. Ngarko vetëm atë që përshtatet. Duke ecur nga më i riu te më i vjetri, shton mesazhe derisa i radhës do ta kalonte faqen mbi 4 MB. Vetëm ato rreshta ngarkohen plotësisht.

Dy rregulla e mbajnë këtë të sigurt:

  • Mesazhi më i ri hyn gjithmonë në faqe, sado i madh të jetë. Një faqe që nuk kthen asgjë do ta linte chat-in të ngecur, pa mënyrë për t’u kthyer mbrapa.
  • Asgjë nuk pritet. Asnjë mesazh nuk shkurtohet apo hiqet. Pjesa tjetër e chat-it ngarkohet përmes kontrollit “Scroll up for earlier messages” që mesazhet më të vjetra përdornin edhe më parë, një faqe në çdo herë.

Gjetëm edhe një vend me të njëjtën formë. Kur ndalon një turn, API-ja kontrollon disa përgjigje të fundit për të parë nëse ndonjëra është bosh dhe duhet pastruar. Këtë e bënte duke ngarkuar tetë mesazhe të plota. Në një chat me përgjigje shumë-megabajtëshe, kjo është e njëjta gjë në formë më të vogël. Tani i bën bazës së të dhënave një pyetje po-ose-jo, a ka këtë mesazh ndonjë përmbajtje?, pa ngarkuar vetë përmbajtjen.

Si e kontrolluam

Në kopjen e chat-it, duke punuar me kufirin e vjetër 384 MiB:

  • Faqja e parë është 5 MB. Më parë e njëjta kërkesë rrëzonte API-n.
  • Pesë skeda shfletuesi që hapin chat-in njëkohësisht arrijnë pikun prej 154 MB memorie.
  • Kthimi nëpër gjithë chat-in kthen të gjitha 190 mesazhet, secili një herë, në rend.

Logjika e zgjedhjes së faqeve ka gjithashtu teste njësi, përfshirë një të ndërtuar nga madhësitë reale të mesazheve më të fundit të atij chat-i. Faqja e parë kthen një mesazh, thotë se ka më shumë, dhe faqja e radhës fillon me atë që vjen pas tij.

Çfarë morëm nga kjo

  • Një numërim nuk është kufi madhësie. Çdo endpoint që kthen “më të rejat N” të diçkaje që mund të rritet pa kufi ka nevojë edhe për një buxhet bajtësh. Të dhënat do ta gjejnë boshllëkun herët a vonë.
  • Dyshimi më i dukshëm nuk është gjithmonë shkaku. Deploy-i ishte një shkak i vërtetë për punë shtesë, dhe më shumë memorie ishte e vlefshme. Por rrëzimi riprodhohej pa deploy, dhe pa e riprodhuar do të ishim ndalur te rritja e memories.
  • Dy servera dështojnë bashkë kur marrin të njëjtën kërkesë. Redundanca mbron nga vdekja e një serveri. Nuk mbron nga një kërkesë që vret çdo server që arrin, sidomos një që përdoruesi do ta riprovojë natyrshëm duke rifreskuar.
  • Rregullo në konfigurim, jo vetëm në makinë. Rritja e memories shkoi në konfigurimin e deploy-it po atë ditë, kështu që deploy-i i radhës e mbajti.

Ky është i dyti nga historitë e fundit të memories që lidhen me daljen e agjentit. I pari ishte një etiketë statusi që vendosi në radhë 690 MB stringje. Nëse përdor nën-agjentë në Mythex, mund të lexosh si funksionojnë në dokumentacion.

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 简体中文 繁體中文(香港) 繁體中文(台灣)