Att väcka databaser utan döda anslutningar
Publicerade appar på Mythex, och deras databaser, går i viloläge när ingen använder dem. När en app vaknade kunde den hålla sin första förfrågan i 10–12 sekunder, eftersom den försökte återanvända databasanslutningar som dött medan allt sov. Vi ger nu Spring Boot-appar databasinställningar som tål viloläge, och säger åt agenten att bygga appar i alla stackar på samma sätt. På hosting-plattformen gick den första förfrågan efter en väckning från 12,7 sekunder till 2,3 sekunder.
Varför appar och databaser går i viloläge
En publicerad Mythex-app kör på en maskin som pausar efter några minuter utan aktivitet, och dess databas är serverless Postgres som går i viloläge efter fem minuter utan aktivitet och vaknar vid nästa förfrågan. Det är det som gör en tyst app billig: du betalar för vad databasen faktiskt använde, och en app i viloläge kostar ingenting i beräkningskraft. Vi skrev om faktureringssidan i att fakturera databaser efter vad de faktiskt använder.
Fallgropen är att de två somnar var för sig, och de är inte överens om vad en anslutning är.
Symptomet: ett långsamt första besök
De flesta serverappar håller en connection pool: ett litet antal öppna databasanslutningar som hålls redo, så att varje förfrågan slipper kostnaden för att öppna en ny. Det är rätt design för en app som alltid är igång.
Så här händer det med viloläge:
- Appen kör, med några inaktiva anslutningar i sin pool.
- Ingen besöker sidan. Appens maskin pausar, frusen, med poolen intakt.
- Databasen går i viloläge och släpper sin ände av varje anslutning.
- En besökare kommer. Appen vaknar precis som den var, med anslutningar som databasen inte längre känner till.
- Poolen ger ut en av dessa anslutningar. Den måste ta reda på att den är död, genom att prova och vänta, innan den ger upp den.
I en Spring Boot-app blockerade valideringen av de döda anslutningarna första förfrågan i ungefär 10 sekunder innan den misslyckades med “Connection is not available”. För besökaren hängde sajten bara, och visade sedan kanske ett fel.
Varför Spring-appar drabbades värst
Spring Boot är ett populärt Java-ramverk, och det använder en connection pool som heter HikariCP som standard. Spring kan konfigurera poolen från inställningar, inklusive hur många inaktiva anslutningar som ska hållas.
Men Mythex ger varje app sin databas som en enda DATABASE_URL i formen postgresql://user:pass@host/db. Spring kan inte läsa det formatet direkt. Så Spring-appar byggda på Mythex konstruerade sin egen pool i koden genom att tolka den URL:en, och en pool byggd för hand ignorerar alla Springs spring.datasource.*-inställningar. Även om någon visste vilka poolinställningar som behövdes fanns det ingen plats där de skulle få effekt.
Lösningen, del 1: inställningar Spring kan använda
När ett projekt har en databas får det nu också miljövariabler som Spring läser direkt:
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAMEochSPRING_DATASOURCE_PASSWORD, konverterade frånDATABASE_URL(med SSL krävt om inte URL:en säger annat).- Poolinställningar som överlever viloläge:
| Inställning | Värde | Varför |
|---|---|---|
| Minsta antal inaktiva anslutningar | 0 | Håll inget öppet mellan förfrågningar, så det finns inget som kan bli inaktuellt |
| Timeout för inaktiva anslutningar | 30 sekunder | Stäng oanvända anslutningar snart |
| Maximal livslängd | 2 minuter | Pensionera varje anslutning innan den hinner bli gammal |
| Timeout för anslutning | 5 sekunder | Låt inte en förfrågan hänga länge om databasen svarar långsamt |
Eftersom inga inaktiva anslutningar hålls öppna öppnar en väckt app en ny anslutning i stället för att ta sig igenom döda.
När dessa variabler finns konfigurerar Spring poolen själv, och inställningarna gäller. Det projektet själv har satt vinner alltid; vi fyller bara i det som saknas. Appar som inte är Spring ignorerar dessa variabler.
Detaljen som nästan gjorde att det inte gjorde någonting
Spring kopplar miljövariabler till sina inställningar enligt en regel som är lätt att göra fel. Inställningen minimum-idle måste skrivas som SPRING_DATASOURCE_HIKARI_MINIMUMIDLE, med bindestrecken borttagna och orden hopskrivna. Skriver man den som SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE, vilket ser mer naturligt ut, kopplas den till en annan, icke-existerande inställning (minimum.idle) och ignoreras tyst.
Det är den sortens misstag som klarar varje granskning och inte gör något i produktion. Så ett test kontrollerar både att värdena är satta och att ingen variabel använder den understreckade formen.
Lösningen, del 2: alla andra stackar
Spring är inte det enda ramverket med en pool, och vi kan inte förkonfigurera varje bibliotek i varje språk. Så Mythex-agenten, AI:n som skriver din app, får nu en generell instruktion för alla stackar: publicerade appar och deras databaser går i viloläge när de är inaktiva, så en anslutning som hålls öppen kan vara död vid nästa förfrågan. Den ska:
- hålla inga inaktiva databasanslutningar öppna, eller kontrollera varje anslutning innan användning,
- försöka igen en gång vid ett anslutningsfel, och
- använda de databasinställningar plattformen tillhandahåller i miljön, i stället för att bygga en egen pool genom att tolka
DATABASE_URL.
Den sista punkten knyter ihop det med del 1: en app som bygger på de tillhandahållna inställningarna får den viloläge-säkra konfigurationen automatiskt.
Resultatet
Mätt på hosting-plattformen där vi kör publicerade appar gick den första förfrågan efter en väckning från 12,7 sekunder till 2,3 sekunder.
Det vi tog med oss
- Varje lager som somnar måste vara överens om vad som överlever. En frusen app och en sovande databas gjorde var och en ett rimligt val. Tillsammans vaknade appen med ett tillstånd som inte längre stämde.
- Standardinställningar gjorda för alltid-igångvarande servrar passar inte appar som skalar till noll. Att hålla anslutningar varma är en bra idé tills allt runt dem blir kallt.
- Ge ramverk deras data i deras eget format. En URL var enkel för oss och tvingade varje Spring-app att handbygga en pool som ignorerade dess egen konfiguration.
- Testa att en inställning stavas så som ramverket läser den. Ett korrekt värde under fel namn gör ingenting, tyst.
Om du är ny till hur databaser fungerar på Mythex, se databasdokumentationen och vår förklaring av vad Postgres är.