Blog

Hvordan én tung chat kunne slå vores API ned

Den 28. september, cirka 17 minutter efter en release, løb begge vores produktions-API-servere tør for hukommelse på samme øjeblik, genstartede, og i omkring fem minutter havde load balanceren ingen sund server at sende trafik til. Vores første rettelse gav API'en dobbelt så meget hukommelse. Den egentlige årsag viste sig senere samme dag: at åbne en bestemt chat fik API'en til at hente 53 MB beskeder i én anmodning. Chathistorik hentes nu i sider, begrænset af størrelse såvel som antal, og den chat åbner med en første side på 5 MB i stedet for et nedbrud.

Hvad der gik ned

Vores API kører som en container på hver af to servere bag en load balancer. Hver container havde en hukommelsesgrænse på 384 MiB. I hvile bruger den 130–140 MiB, så grænsen så ud til at have masser af luft.

Begge containere ramte grænsen samtidig og styrtede med „JavaScript heap out of memory“. Heapen er den hukommelse, en Node.js-proces bruger til de objekter, den arbejder med. Fordi begge servere fejlede på én gang, var der ingen steder tilbage at sende anmodninger hen. Det er den værst tænkelige type nedetid for et opsætning med to servere: redundans hjælper kun, når fejlene ikke rammer samtidig.

Den første rettelse: mere plads

Tidspunktet pegede på deployet. Efter en release genoptages agentforløb, som deployet afbrød, og de gemmer deres transskripter igen. Den burst af arbejde lignede den åbenlyse kilde til en hukommelsestop.

Så den første ændring hævede API'ens grænse fra 384 MiB til 768 MiB. Vi anvendte den live på begge servere samme dag og committede den til deploy-konfigurationen, så næste deploy ikke stille og roligt sætter 384 tilbage. En rettelse lavet i hånden på en server, som næste deploy så fortryder, er en almindelig måde at få den samme nedetid tilbage på.

Mere hukommelse var en fornuftig sikkerhedsmargen. Det var ikke en forklaring.

Den egentlige årsag: én anmodning, 71 MB

Senere samme dag reproducerede vi nedbruddet på en kopi af én chat med produktionens gamle hukommelsesgrænse. Kopien styrtede API'en alene, uden at et deploy var involveret.

Når du åbner et projekt, beder webappen API'en om chatens historik. Endepunktet returnerede de nyeste 30 beskeder, hele. For de fleste chats er 30 beskeder småt. For denne chat var de nyeste 30 beskeder 53 MB i databasen og et svar på 71 MB. Flere af agentens svar var 4–10 MB hver, mest transskripter fra under-agenter: de hjælperagenter, hovedagenten starter for at arbejde på en del af en opgave parallelt, og hvis fulde arbejde gemmes sammen med svaret.

At bygge det ene svar krævede mere heap, end API'en havde. Og hver gang man åbnede eller opdaterede projektet, blev anmodningen sendt igen. Én chat kunne slå den server ned, den landede på, og fordi siden kunne genindlæses, kunne den nå begge.

„30 beskeder“ havde aldrig været en reel grænse for størrelse. Det var en grænse for antal, som tilfældigvis var lille for normale chats.

Rettelsen: sider begrænset af størrelse såvel som antal

En side med historik er nu 30 beskeder eller cirka 4 MB af dem, alt efter hvad der kommer først.

Det virker i to trin:

  1. Spørg først efter størrelser. API'en beder databasen om ID'erne og de gemte størrelser for de nyeste beskeder, uden deres indhold. Den forespørgsel er billig, uanset hvor store beskederne er.
  2. Hent kun det, der passer. Den går fra nyeste til ældste og tilføjer beskeder, indtil den næste ville skubbe siden over 4 MB. Kun de rækker hentes derefter i fuld længde.

To regler holder det sikkert:

  • Den nyeste besked kommer altid med på siden, uanset størrelse. En side, der ikke returnerede noget, ville efterlade chatten fast uden mulighed for at scrolle tilbage.
  • Intet skæres af. Ingen besked afkortes eller droppes. Resten af chatten hentes via kontrollen „Scroll up for earlier messages“, som ældre beskeder allerede brugte, én side ad gangen.

Vi fandt endnu et sted med samme form. Når du stopper et forløb, tjekker API'en de sidste par svar for at se, om nogen er tomme og skal ryddes op. Det gjorde den ved at hente otte hele beskeder. På en chat med svar på flere megabyte er det det samme problem i en mindre form. Nu stiller den databasen et ja-eller-nej-spørgsmål — har denne besked noget indhold? — uden selv at hente indholdet.

Sådan testede vi det

På kopien af chatten, kørende med den gamle grænse på 384 MiB:

  • Den første side er 5 MB. Før styrtede den samme anmodning API'en.
  • Fem browserfaner, der åbner chatten samtidig, topper på 154 MB hukommelse.
  • At scrolle tilbage gennem hele chatten returnerer alle 190 beskeder, hver præcis én gang, i rækkefølge.

Logikken for at vælge sider har også enhedstests, herunder én bygget på de reelle størrelser af den chats nyeste beskeder. Den første side kommer tilbage med én besked, siger at der er flere, og næste side starter ved den efter den.

Hvad vi tog med

  • Et antal er ikke en størrelsesgrænse. Ethvert endepunkt, der returnerer „de nyeste N“ af noget, der kan vokse uden grænse, har også brug for et byte-budget. Dataene finder hullet til sidst.
  • Den åbenlyse mistænkte er ikke altid årsagen. Deployet var en reel udløser for ekstra arbejde, og mere hukommelse var værd at have. Men nedbruddet kunne reproduceres uden et deploy, og uden at reproducere det ville vi være stoppet ved hukommelsesforøgelsen.
  • To servere fejler sammen, når de får den samme anmodning. Redundans beskytter mod, at én server dør. Den beskytter ikke mod en anmodning, der slår enhver server ned, den rammer — især en, som en bruger naturligt vil gentage ved at opdatere siden.
  • Ret det i konfigurationen, ikke kun på maskinen. Hukommelsesforøgelsen gik ind i deploy-konfigurationen samme dag, så næste deploy beholdt den.

Dette er vores anden nylige hukommelseshistorie, der involverer agentens output. Den første var en statuslabel, der satte 690 MB strenge i kø. Hvis du bruger under-agenter på Mythex, kan du læse om, hvordan de virker, i dokumentationen.

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