Prebúdzanie databáz bez mŕtvych spojení
Publikované aplikácie na Mythexe a ich databázy zaspia, keď ich nikto nepoužíva. Keď sa aplikácia prebudila, prvú požiadavku mohla držať 10–12 sekúnd, pretože sa pokúšala znovu použiť databázové spojenia, ktoré počas spánku všetkého odumreli. Teraz dávame Spring Boot aplikáciám databázové nastavenia, ktoré sú bezpečné aj po spánku, a agentovi hovoríme, aby aplikácie akéhokoľvek stacku budoval rovnako. Na hostingovej platforme sa prvá požiadavka po prebudení zmenila z 12,7 sekundy na 2,3 sekundy.
Prečo aplikácie a databázy spia
Publikovaná aplikácia Mythex beží na stroji, ktorý sa po pár minútach nečinnosti uspí, a jej databáza je serverless Postgres, ktorá zaspí po piatich minútach nečinnosti a prebudí sa pri ďalšej požiadavke. Práve to drží tichú aplikáciu lacnú: platíte za to, čo databáza skutočne použila, a spiaca aplikácia nestojí nič za výpočtový výkon. O fakturačnej stránke sme písali v článku účtovanie databáz podľa toho, čo skutočne využívajú.
Háčik je v tom, že obe zložky zaspávajú oddelene a nesúhlasia v tom, čo je spojenie.
Symptóm: pomalá prvá návšteva
Väčšina serverových aplikácií používa connection pool: zopár otvorených databázových spojení, ktoré sú pripravené, takže každá požiadavka nemusí platiť za otvorenie nového. Pre aplikáciu, ktorá beží stále, je to správny návrh.
Pri spánku sa stane toto:
- Aplikácia beží a v poole má niekoľko nečinných spojení.
- Nikto nepríde. Stroj aplikácie sa uspí — zmrazený aj s poolom.
- Databáza zaspí a zruší svoj koniec každého spojenia.
- Návštevník príde. Aplikácia sa prebudí presne tak, ako bola, a stále drží spojenia, o ktorých databáza už nevie.
- Pool vydá jedno z týchto spojení. Pred jeho zahodením musí zistiť, že je mŕtve — vyskúšaním a čakaním.
V aplikácii Spring Boot overovanie mŕtvych spojení blokovalo prvú požiadavku asi 10 sekúnd, kým zlyhala s hláškou „Connection is not available“. Pre návštevníka sa stránka jednoducho zasekla a potom možno ukázala chybu.
Prečo Spring aplikácie dostali najviac
Spring Boot je populárny Java framework a predvolene používa connection pool HikariCP. Spring vie tento pool nakonfigurovať z nastavení, vrátane toho, koľko nečinných spojení sa má držať.
Mythex však dáva každej aplikácii databázu ako jednu premennú DATABASE_URL v tvare postgresql://user:pass@host/db. Spring tento formát nevie priamo prečítať. Spring aplikácie postavené na Mythexe si preto pool vytvárali v kóde parsovaním tejto URL — a pool vytvorený ručne ignoruje všetky nastavenia spring.datasource.*. Aj keby niekto poznal správne nastavenia poolu, nemal kde sa prejaviť.
Oprava, časť 1: nastavenia, ktoré Spring vie použiť
Keď projekt má databázu, teraz mu dávame aj premenné prostredia, ktoré Spring číta natívne:
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAMEaSPRING_DATASOURCE_PASSWORD, odvodené zDATABASE_URL(s vyžadovaným SSL, pokiaľ URL nehovorí inak).- Nastavenia poolu, ktoré prežijú spánok:
| Nastavenie | Hodnota | Prečo |
|---|---|---|
| Minimálny počet nečinných spojení | 0 | Medzi požiadavkami nič neotvárať, takže nie je čo zastarať |
| Idle timeout | 30 sekúnd | Rýchlo zatvárať nepoužité spojenia |
| Maximálna životnosť | 2 minúty | Ukončiť každé spojenie skôr, než môže zostarnúť |
| Connection timeout | 5 sekúnd | Nedržať požiadavku dlho, ak databáza odpovedá pomaly |
Keď nedržíte žiadne nečinné spojenia, prebudená aplikácia otvorí jedno nové spojenie namiesto toho, aby sa brodila mŕtvymi.
Keď sú tieto premenné prítomné, Spring pool nakonfiguruje sám a nastavenia sa uplatnia. Čokoľvek projekt nastavil sám, má vždy prednosť; my doplňujeme len to, čo chýba. Aplikácie, ktoré nie sú v Springu, tieto premenné ignorujú.
Detail, ktorý to takmer nechal bez účinku
Spring mapuje premenné prostredia na svoje nastavenia podľa pravidla, ktoré sa ľahko pokazí. Nastavenie minimum-idle sa musí zapísať ako SPRING_DATASOURCE_HIKARI_MINIMUMIDLE — pomlčky vynechané, slová spojené dohromady. Zápis SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE, ktorý vyzerá prirodzenejšie, sa mapuje na iné, neexistujúce nastavenie (minimum.idle) a je ticho ignorovaný.
Takáto chyba prejde každou kontrolou a v produkcii nerobí nič. Preto test kontroluje, že hodnoty sú nastavené, a zároveň že žiadna premenná nepoužíva tvar s podčiarkovníkmi.
Oprava, časť 2: každý iný stack
Spring nie je jediný framework s poolom a nevieme vopred nakonfigurovať každú knižnicu v každom jazyku. Agent Mythex — AI, ktorá píše vašu aplikáciu — preto teraz dostáva trvalú inštrukciu pre akýkoľvek stack: publikované aplikácie a ich databázy zaspávajú pri nečinnosti, takže spojenie držané otvorené môže byť pri ďalšej požiadavke mŕtve. Mal by:
- nedržať žiadne nečinné databázové spojenia otvorené, alebo každé pred použitím overiť,
- pri chybe spojenia skúsiť požiadavku zopakovať raz a
- používať databázové nastavenia, ktoré platforma poskytuje v prostredí, namiesto toho, aby si pool stavala sama parsovaním
DATABASE_URL.
Tá posledná časť uzatvára kruh s časťou 1: aplikácia postavená na poskytnutých nastaveniach automaticky získa konfiguráciu bezpečnú pre spánok.
Výsledok
Merané na hostingovej platforme, kde beží naše publikované aplikácie, sa prvá požiadavka po prebudení zmenila z 12,7 sekundy na 2,3 sekundy.
Čo sme si z toho odniesli
- Každá vrstva, ktorá spí, musí súhlasiť v tom, čo prežije. Zmrazená aplikácia a uspaná databáza urobili každá rozumnú voľbu. Spolu však aplikácia prebudila so stavom, ktorý už neplatil.
- Predvolené nastavenia navrhnuté pre servery, ktoré bežia stále, nesedia na aplikácie, ktoré sa škálujú na nulu. Držať spojenia teplé je dobrý nápad, kým všetko okolo nevychladne.
- Dajte frameworkom dáta v ich vlastnom formáte. Jedna URL bola pre nás jednoduchá, no každú Spring aplikáciu nútila ručne skladať pool, ktorý ignoroval vlastnú konfiguráciu.
- Otestujte, že nastavenie je napísané tak, ako ho framework číta. Správna hodnota pod zlým názvom nerobí nič, a to ticho.
Ak ste na Mythexe noví a chcete vedieť, ako fungujú databázy, pozrite si dokumentáciu k databázam a náš návod čo je Postgres.