Vågn databaser op uden døde forbindelser
Publicerede apps på Mythex og deres databaser går i dvale, når ingen bruger dem. Når en app vågnede, kunne den holde sin første forespørgsel i 10–12 sekunder, fordi den forsøgte at genbruge databaseforbindelser, der var døde, mens alt sov. Nu giver vi Spring Boot-apps databaseindstillinger, der er sikre på tværs af dvale, og vi beder agenten bygge apps i enhver stack på samme måde. På hostingplatformen gik den første forespørgsel efter en opvågning fra 12,7 sekunder til 2,3 sekunder.
Hvorfor apps og databaser går i dvale
En publiceret Mythex-app kører på en maskine, der suspenderer efter få minutters inaktivitet, og dens database er serverless Postgres, der går i dvale efter fem minutters inaktivitet og vågner ved den næste forespørgsel. Det er det, der holder en stille app billig: du betaler for det, databasen faktisk bruger, og en sovende app bruger ingen compute. Vi skrev om faktureringsdelen i billing af databaser efter, hvad de faktisk bruger.
Faldgruppen er, at de to sover hver for sig, og de er ikke enige om, hvad en forbindelse er.
Symptomet: et langsomt første besøg
De fleste serverapps holder en connection pool: et lille antal åbne databaseforbindelser, der holdes klar, så hver forespørgsel ikke skal betale for at åbne en ny. Det er det rigtige design for en app, der altid er tændt.
Så sker dette med dvale:
- Appen kører med et par inaktive forbindelser i sin pool.
- Ingen besøger. Appens maskine suspenderes — frosset, med poolen intakt.
- Databasen går i dvale og taber sin ende af hver forbindelse.
- En besøgende ankommer. Appen vågner præcis, som den var, og holder stadig forbindelser, databasen ikke længere kender.
- Poolen udleverer en af de forbindelser. Den skal finde ud af, at den er død — ved at prøve den og vente — før den opgiver den.
I en Spring Boot-app blokerede validering af de døde forbindelser den første forespørgsel i omkring 10 sekunder, før den fejlede med "Connection is not available". For den besøgende hang siden simpelthen og viste måske så en fejl.
Hvorfor Spring-apps fik det værst
Spring Boot er et populært Java-framework, og det bruger som standard en connection pool ved navn HikariCP. Spring kan konfigurere den pool fra indstillinger, herunder hvor mange inaktive forbindelser der holdes.
Men Mythex giver hver app sin database som en enkelt DATABASE_URL i formen postgresql://user:pass@host/db. Spring kan ikke læse det format direkte. Så Spring-apps bygget på Mythex konstruerede deres egen pool i kode ved at parse den URL — og en pool bygget i hånden ignorerer alle Springs spring.datasource.*-indstillinger. Selv hvis nogen kendte de rigtige pool-indstillinger, var der ingen steder, de ville få effekt.
Rettelsen, del 1: indstillinger Spring kan bruge
Når et projekt har en database, giver vi nu også miljøvariabler, som Spring læser direkte:
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAMEogSPRING_DATASOURCE_PASSWORD, konverteret fraDATABASE_URL(med SSL påkrævet, medmindre URL'en siger andet).- Pool-indstillinger, der overlever dvale:
| Indstilling | Værdi | Hvorfor |
|---|---|---|
| Minimum inaktive forbindelser | 0 | Hold intet åbent mellem forespørgsler, så der ikke er noget, der bliver forældet |
| Inaktivitetstimeout | 30 sekunder | Luk ubrugte forbindelser hurtigt |
| Maksimal levetid | 2 minutter | Pensionér hver forbindelse, før den kan blive gammel |
| Forbindelsestimeout | 5 sekunder | Lad ikke en forespørgsel hænge længe, hvis databasen svarer langsomt |
Når der ikke holdes inaktive forbindelser, åbner en opvågnet app én frisk forbindelse i stedet for at vade igennem døde.
Når disse variabler er til stede, konfigurerer Spring selv poolen, og indstillingerne gælder. Det, projektet selv har sat, vinder altid; vi udfylder kun det, der mangler. Apps der ikke er Spring ignorerer disse variabler.
Detaljen, der næsten gjorde, at det ikke virkede
Spring mapper miljøvariabler til sine indstillinger efter en regel, der er nem at tage fejl af. Indstillingen minimum-idle skal skrives som SPRING_DATASOURCE_HIKARI_MINIMUMIDLE — bindestreger droppet, ord sat sammen. Skriver man den som SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE, der ser mere naturligt ud, mapper den til en anden, ikke-eksisterende indstilling (minimum.idle) og ignoreres stille.
Det er den slags fejl, der går igennem enhver gennemgang og ingenting gør i produktion. Så en test kontrollerer både, at værdierne er sat, og at ingen variabel bruger den underscore-adskilte form.
Rettelsen, del 2: alle andre stacks
Spring er ikke det eneste framework med en pool, og vi kan ikke forkonfigurere hvert bibliotek i hvert sprog. Så Mythex-agenten — AI'en, der skriver din app — får nu en fast instruktion for enhver stack: publicerede apps og deres databaser går i dvale, når de er inaktive, så en forbindelse, der holdes åben, kan være død ved den næste forespørgsel. Den bør:
- ikke holde inaktive databaseforbindelser åbne, eller tjekke hver enkelt før brug,
- forsøge igen én gang ved en forbindelsesfejl, og
- bruge de databaseindstillinger, platformen leverer i miljøet, i stedet for selv at bygge en pool ved at parse
DATABASE_URL.
Det sidste punkt lukker sløjfen med del 1: en app bygget på de leverede indstillinger får automatisk den dvale-sikre konfiguration.
Resultatet
Målt på den hostingplatform, vi kører publicerede apps på, gik den første forespørgsel efter en opvågning fra 12,7 sekunder til 2,3 sekunder.
Det vi tog med
- Hvert lag, der sover, skal være enige om, hvad der overlever. En frosset app og en sovende database traf hver et rimeligt valg. Sammen vågnede appen op med en tilstand, der ikke længere var sand.
- Standarder designet til altid-tændte servere passer ikke til apps, der skalerer til nul. At holde forbindelser varme er en god idé, indtil alt omkring dem bliver koldt.
- Giv frameworks deres data i deres eget format. Én URL var enkel for os og tvang hver Spring-app til at håndbygge en pool, der ignorerede sin egen konfiguration.
- Test at en indstilling er stavet, som frameworket læser den. En korrekt værdi under det forkerte navn gør ingenting, og det uden at sige noget.
Hvis du er ny til, hvordan databaser fungerer på Mythex, se database-dokumentationen og vores forklaring om hvad Postgres er.