Buđenje baza podataka bez mrtvih veza
Objavljene aplikacije na Mythexu i njihove baze podataka zaspu kad ih nitko ne koristi. Kad bi se aplikacija probudila, prvi zahtjev mogao je trajati 10–12 sekundi, jer je pokušavala ponovno koristiti veze prema bazi koje su umrle dok je sve spavalo. Sada Spring Boot aplikacijama dajemo postavke baze koje su sigurne nakon spavanja i govorimo agentu da sve aplikacije, bez obzira na stog, grade na isti način. Na hosting platformi prvi zahtjev nakon buđenja smanjio se s 12,7 sekundi na 2,3 sekunde.
Zašto aplikacije i baze spavaju
Objavljena Mythex aplikacija radi na stroju koji se suspendira nakon nekoliko minuta mirovanja, a njezina baza je serverless Postgres koji zaspi nakon pet minuta neaktivnosti i probudi se na sljedeći upit. Time tiha aplikacija ostaje jeftina: plaćate ono što baza stvarno iskoristi, a spavajuća aplikacija ne troši ništa na računalnu snagu. O naplatnoj strani pisali smo u naplati baza prema onome što stvarno koriste.
Ulov je u tome što njih dvoje zaspu odvojeno i ne slažu se oko toga što je veza.
Simptom: spor prvi posjet
Većina serverskih aplikacija drži connection pool: nekoliko otvorenih veza prema bazi koje su spremne, pa svaki zahtjev ne plaća trošak otvaranja nove. To je ispravan dizajn za aplikaciju koja je uvijek aktivna.
Evo što se događa sa spavanjem:
- Aplikacija radi, s nekoliko neaktivnih veza u poolu.
- Nitko ne posjećuje. Stroj aplikacije se suspendira, zamrznut, s netaknutim poolom.
- Baza zaspi i odbaci svoj kraj svake veze.
- Posjetitelj dolazi. Aplikacija se budi točno onakva kakva je bila, još uvijek s vezama za koje baza više ne zna.
- Pool izdaje jednu od tih veza. Mora otkriti da je mrtva, pokušajem i čekanjem, prije nego što je odbaci.
U Spring Boot aplikaciji validacija tih mrtvih veza blokirala je prvi zahtjev oko 10 sekundi prije nego što je pao s porukom „Connection is not available”. Za posjetitelja je stranica jednostavno visjela, pa bi se tek onda pojavila greška.
Zašto su Spring aplikacije najviše stradale
Spring Boot je popularan Java okvir, a po zadanom koristi pool veza HikariCP. Spring može konfigurirati taj pool iz postavki, uključujući koliko neaktivnih veza održavati.
Ali Mythex svakoj aplikaciji daje bazu kao jedan DATABASE_URL u obliku postgresql://user:pass@host/db. Spring taj format ne može izravno čitati. Zato su Spring aplikacije izgrađene na Mythexu sami konstruirali pool u kodu, parsirajući taj URL, a pool napravljen ručno ignorira sve Springove postavke spring.datasource.*. Čak i kad bi netko znao ispravne postavke poola, nije bilo mjesta gdje bi one stupile na snagu.
Popravak, dio 1: postavke koje Spring može koristiti
Kad projekt ima bazu, sada dobiva i varijable okoline koje Spring čita izvorno:
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAMEiSPRING_DATASOURCE_PASSWORD, pretvorene izDATABASE_URL(uz zahtjev za SSL osim ako URL to drukčije kaže).- Postavke poola koje prežive spavanje:
| Postavka | Vrijednost | Zašto |
|---|---|---|
| Minimalni broj neaktivnih veza | 0 | Između zahtjeva ne držimo ništa otvoreno, pa nema ničega što bi zastarjelo |
| Idle timeout | 30 sekundi | Neiskorištene veze zatvaraju se brzo |
| Maksimalni životni vijek | 2 minute | Svaka veza se povuče prije nego što može ostarjeti |
| Connection timeout | 5 sekundi | Zahtjev ne visi dugo ako baza sporo odgovara |
Kad se ne drže neaktivne veze, probuđena aplikacija otvara jednu svježu vezu umjesto da se probija kroz mrtve.
Kad su te varijable prisutne, Spring sam konfigurira pool i postavke se primjenjuju. Ono što je projekt sam postavio uvijek ima prednost; mi popunjavamo samo ono što nedostaje. Aplikacije koje nisu Spring ignoriraju te varijable.
Detalj koji je zamalo sve pokvario
Spring preslikava varijable okoline na svoje postavke pravilom koje je lako pogriješiti. Postavka minimum-idle mora se pisati kao SPRING_DATASOURCE_HIKARI_MINIMUMIDLE: crtice izostavljene, riječi spojene. Ako napišete SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE, što izgleda prirodnije, preslikava se na drugu, nepostojeću postavku (minimum.idle) i tiho se ignorira.
To je vrsta greške koja prolazi svaki pregled i ništa ne radi u produkciji. Zato test provjerava i da su vrijednosti postavljene i da nijedna varijabla ne koristi oblik s podvlakama.
Popravak, dio 2: svi ostali stogovi
Spring nije jedini okvir s poolom, a ne možemo unaprijed konfigurirati svaku biblioteku u svakom jeziku. Zato AI agent koji piše vašu aplikaciju sada ima trajnu uputu za bilo koji stog: objavljene aplikacije i njihove baze spavaju kad su neaktivne, pa veza koja je ostala otvorena može biti mrtva pri sljedećem zahtjevu. Agent bi trebao:
- ne držati neaktivne veze prema bazi otvorene ili provjeriti svaku prije upotrebe,
- jednom ponovno pokušati pri grešci veze, i
- koristiti postavke baze koje platforma daje u okolini, a ne graditi vlastiti pool parsiranjem
DATABASE_URL.
Ta posljednja točka zatvara krug s dijelom 1: aplikacija izgrađena na postavkama koje platforma daje automatski preuzima konfiguraciju sigurnu za spavanje.
Rezultat
Izmjereno na hosting platformi na kojoj radimo objavljene aplikacije, prvi zahtjev nakon buđenja smanjio se s 12,7 sekundi na 2,3 sekunde.
Što smo iz toga izvukli
- Svaki sloj koji spava mora se slagati oko toga što preživljava. Zamrznuta aplikacija i uspavana baza donijele su svaka razumnu odluku. Zajedno, aplikacija se probudila sa stanjem koje više nije bilo istinito.
- Zadane postavke osmišljene za servere koji su uvijek aktivni ne pristaju aplikacijama koje se skaliraju na nulu. Držati veze tople dobra je ideja dok se sve oko njih ne ohladi.
- Dajte okvirima njihove podatke u njihovom formatu. Jedan URL bio je jednostavan za nas, a svaku Spring aplikaciju prisiljavao je da ručno napravi pool koji ignorira vlastitu konfiguraciju.
- Testirajte da je postavka napisana onako kako je okvir čita. Ispravna vrijednost pod pogrešnim imenom ne radi ništa, tiho.
Ako ste novi u tome kako baze rade na Mythexu, pogledajte dokumentaciju o bazama i naš tekst o tome što je Postgres.