Probouzení databází bez mrtvých spojení
Publikované aplikace na Mythexu i jejich databáze po čase nečinnosti usínají. Když se aplikace probudila, mohla první požadavek držet 10–12 sekund, protože se pokoušela znovu použít databázová spojení, která během spánku všechna odumřela. Nyní dáváme Spring Boot aplikacím nastavení databáze, které je bezpečné i přes spánek, a agentovi říkáme, aby stavěl aplikace jakéhokoli stacku stejným způsobem. Na hostingové platformě se první požadavek po probuzení zkrátil z 12,7 sekundy na 2,3 sekundy.
Proč aplikace a databáze usínají
Publikovaná aplikace na Mythexu běží na stroji, který se po několika minutách nečinnosti pozastaví, a její databáze je bezserverový Postgres, který usne po pěti minutách nečinnosti a probudí se při dalším dotazu. To udržuje tichou aplikaci levnou: platíte za to, co databáze skutečně využila, a usínající aplikace nic nestojí za výpočetní výkon. Psali jsme o účtování té části v článku účtování databází podle skutečného využití.
Spíš je to past: oba usínají samostatně a nesouhlasí v tom, co je spojení.
Příznak: pomalá první návštěva
Většina serverových aplikací drží connection pool: hrstku otevřených databázových spojení připravených k použití, takže každý požadavek neplatí cenu otevření nového. Pro aplikaci, která je pořád zapnutá, je to správný návrh.
Tady je, co se děje při spánku:
- Aplikace běží s několika nečinnými spojeními v poolu.
- Nikdo nenavštíví. Stroj aplikace se pozastaví – zmrazený, s poolem nedotčeným.
- Databáze usne a zavře svůj konec všech spojení.
- Přijde návštěvník. Aplikace se probudí přesně tak, jak byla, pořád držíc spojení, o kterých databáze už neví.
- Pool předá jedno z těchto spojení. Musí zjistit, že je mrtvé – zkusit ho použít a počkat –, než se ho vzdá.
Ve Spring Boot aplikaci validace těchto mrtvých spojení blokovala první požadavek zhruba 10 sekund, než selhal s chybou „Connection is not available“. Pro návštěvníka web prostě visel a pak možná ukázal chybu.
Proč to nejvíc schytaly aplikace Springu
Spring Boot je populární Java framework a ve výchozím nastavení používá connection pool jménem HikariCP. Spring může ten pool nastavit z konfigurace, včetně toho, kolik nečinných spojení držet.
Mythex ale dává každé aplikaci její databázi jako jediné DATABASE_URL ve tvaru postgresql://user:pass@host/db. Spring tento formát nečte přímo. Aplikace Springu postavené na Mythexu si proto pool vytvářely v kódu parsováním té URL – a pool sestavený ručně ignoruje všechna nastavení spring.datasource.*. I kdyby někdo znal správná nastavení poolu, neměla by kde se projevit.
Oprava, část 1: nastavení, které Spring umí použít
Když projekt má databázi, nyní dostává také proměnné prostředí, které Spring čte nativně:
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAMEaSPRING_DATASOURCE_PASSWORD, převedené zDATABASE_URL(s vyžadovaným SSL, pokud URL neříká jinak).- Nastavení poolu, která přežijí spánek:
| Nastavení | Hodnota | Proč |
|---|---|---|
| Minimum nečinných spojení | 0 | Mezi požadavky nic neudržovat otevřené, takže nic nezastará |
| Časový limit nečinnosti | 30 sekund | Nepoužívaná spojení brzy zavřít |
| Maximální životnost | 2 minuty | Ukončit každé spojení dřív, než zestárne |
| Časový limit spojení | 5 sekund | Nenechat požadavek viset dlouho, pokud databáze odpovídá pomalu |
Když aplikace nedrží žádná nečinná spojení, probuzená aplikace otevře jedno čerstvé místo toho, aby se brodila mrtvými.
Pokud jsou tyto proměnné přítomné, Spring nastaví pool sám a nastavení se uplatní. Cokoli, co projekt nastavil sám, má vždy přednost; my doplňujeme jen to, co chybí. Aplikace, které nejsou Spring, tyto proměnné ignorují.
Detail, který málem nedělal nic
Spring mapuje proměnné prostředí na svá nastavení podle pravidla, které se snadno splete. Nastavení minimum-idle se musí psát jako SPRING_DATASOURCE_HIKARI_MINIMUMIDLE – pomlčky vynechané, slova spojená dohromady. Napsané jako SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE, což vypadá přirozeněji, se namapuje na jiné, neexistující nastavení (minimum.idle) a je tiše ignorováno.
Takový omyl projde každou kontrolou a v produkci nic nedělá. Proto test ověřuje jak to, že hodnoty jsou nastavené, tak to, že žádná proměnná nepoužívá tvar s podtržítky.
Oprava, část 2: všechny ostatní stacky
Spring není jediný framework s poolem a nemůžeme předkonfigurovat každou knihovnu v každém jazyce. Agent Mythexu – AI, která píše vaši aplikaci – proto nyní dostává trvalou instrukci pro každý stack: publikované aplikace a jejich databáze při nečinnosti usínají, takže spojení, které se drželo otevřené, může být při dalším požadavku mrtvé. Měl by:
- nedržet žádná nečinná databázová spojení otevřená, nebo každé před použitím ověřit,
- jednou zopakovat požadavek při chybě spojení, a
- používat nastavení databáze, které platforma poskytuje v prostředí, místo aby si vytvářel vlastní pool parsováním
DATABASE_URL.
Poslední bod uzavírá smyčku s částí 1: aplikace postavená na poskytnutém nastavení automaticky převezme konfiguraci bezpečnou při spánku.
Výsledek
Měřeno na hostingové platformě, na které běží publikované aplikace, se první požadavek po probuzení zkrátil z 12,7 sekundy na 2,3 sekundy.
Co jsme si z toho odnesli
- Každá vrstva, která usíná, musí souhlasit s tím, co přežije. Zmrazená aplikace a usnulá databáze udělaly každá rozumnou volbu. Dohromady se aplikace probudila s stavem, který už nebyl pravdivý.
- Výchozí hodnoty navržené pro servery běžící pořád se nehodí na aplikace, které se škálují na nulu. Udržovat spojení teplá je dobrý nápad, dokud okolí nevychladne.
- Dejte frameworkům data v jejich vlastním formátu. Jedna URL byla pro nás jednoduchá, ale nutila každou Spring aplikaci ručně psát pool, který ignoroval vlastní konfiguraci.
- Ověřte, že nastavení je napsané tak, jak ho framework čte. Správná hodnota pod špatným jménem nedělá nic, a tiše.
Pokud se v Mythexu teprve orientujete v databázích, podívejte se do dokumentace k databázím a do našeho vysvětlení co je Postgres.