Adatbázisok felébresztése halott kapcsolatok nélkül
A Mythexen publikált appok és adatbázisaik elalszanak, amikor senki nem használja őket. Amikor egy app felébredett, az első kérését 10–12 másodpercig tarthatta, mert olyan adatbázis-kapcsolatokat próbált újrahasználni, amelyek az egész rendszer alvása alatt elhaltak. Most a Spring Boot appoknak olyan adatbázis-beállításokat adunk, amelyek alvás után is biztonságosak, és az ügynöknek azt mondjuk, hogy bármilyen stackű appot ugyanígy építsen. A hosting platformon az első kérés az ébredés után 12,7 másodpercről 2,3 másodpercre csökkent.
Miért alszanak az appok és az adatbázisok
A publikált Mythex-app egy gépen fut, amely néhány perc tétlenség után felfüggesztődik, az adatbázisa pedig szerver nélküli Postgres, amely öt tétlen perc után alszik el, és a következő lekérdezésre ébred. Ez tartja olcsón a csendes appot: az adatbázis-használatot a ténylegesen felhasznált mennyiség szerint fizeted, egy alvó app pedig nem költ számítási kapacitásra. A számlázási oldalról az adatbázisok a ténylegesen használt mennyiség szerint bejegyzésben írtunk.
A probléma az, hogy a kettő külön alszik el, és nem értenek egyet abban, mi is egy kapcsolat.
A tünet: lassú első látogatás
A legtöbb szerver-app kapcsolat-készletet (connection pool) tart fenn: néhány nyitott adatbázis-kapcsolat készenlétben, hogy minden kérésnek ne kelljen új kapcsolatot nyitnia. Ez helyes tervezés egy mindig élő app számára.
Alvásnál a következő történik:
- Az app fut, néhány tétlen kapcsolattal a készletében.
- Senki nem látogat meg. Az app gépe felfüggesztődik — befagyasztva, a készletével együtt.
- Az adatbázis elalszik, és elejti minden kapcsolat másik végét.
- Érkezik egy látogató. Az app pontosan úgy ébred, ahogy volt, még mindig olyan kapcsolatokat tartva, amelyekről az adatbázis már nem tud.
- A készlet az egyik ilyen kapcsolatot adja ki. Ki kell derítenie, hogy halott — úgy, hogy megpróbálja, és vár —, mielőtt feladná.
Egy Spring Boot appban a halott kapcsolatok validálása nagyjából 10 másodpercig blokkolta az első kérést, mielőtt az „A kapcsolat nem elérhető” hibával meghiúsult volna. A látogató számára az oldal egyszerűen lefagyott, aztán esetleg hibát mutatott.
Miért kapták a Spring-appok a legrosszabbat
A Spring Boot egy népszerű Java-keretrendszer, amely alapértelmezetten a HikariCP nevű kapcsolat-készletet használja. A Spring a készletet beállításokból is konfigurálhatja, beleértve, hány tétlen kapcsolatot tartson fenn.
De a Mythex minden appnak az adatbázisát egyetlen DATABASE_URL környezeti változóként adja, postgresql://user:pass@host/db formában. A Spring ezt a formátumot nem tudja közvetlenül olvasni. Így a Mythexen épített Spring-appok a készletet maguk építették kódban, az URL elemzésével — és a kézzel épített készlet figyelmen kívül hagy minden spring.datasource.* beállítást. Még ha valaki ismerte is a helyes készletbeállításokat, nem volt olyan hely, ahol azok érvényesülhettek volna.
A javítás, 1. rész: Spring által használható beállítások
Ha egy projektnek van adatbázisa, most olyan környezeti változókat is kap, amelyeket a Spring natívan olvas:
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAMEésSPRING_DATASOURCE_PASSWORD, aDATABASE_URL-ből átalakítva (SSL-t megköveteljük, hacsak az URL nem mond mást).- Készletbeállítások, amelyek túlélik az alvást:
| Beállítás | Érték | Miért |
|---|---|---|
| Minimális tétlen kapcsolatok | 0 | Kérések között nem tartunk nyitva semmit, így nincs mi elavuljon |
| Tétlenségi időkorlát | 30 másodperc | A nem használt kapcsolatok hamar bezárulnak |
| Maximális élettartam | 2 perc | Minden kapcsolat nyugdíjba megy, mielőtt megöregedne |
| Kapcsolódási időkorlát | 5 másodperc | Ne tartson egy kérést sokáig, ha az adatbázis lassan válaszol |
Tétlen kapcsolat nélkül a felébredt app egyetlen friss kapcsolatot nyit a halott kapcsolatok átrágása helyett.
Ha ezek a változók jelen vannak, a Spring maga konfigurálja a készletet, és a beállítások érvényesülnek. Ami a projektben már be van állítva, az mindig győz; mi csak azt töltjük ki, ami hiányzik. A nem Spring appok figyelmen kívül hagyják ezeket a változókat.
A részlet, ami majdnem semmit sem csinált
A Spring a környezeti változókat a beállításaihoz egy szabály szerint rendeli, amelyet könnyű elrontani. A minimum-idle beállítást SPRING_DATASOURCE_HIKARI_MINIMUMIDLE alakban kell írni — a kötőjelek kimaradnak, a szavak összeolvadnak. A SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE alakban, amely természetesebbnek tűnik, egy másik, nem létező beállításhoz (minimum.idle) kötődik, és csendben figyelmen kívül marad.
Ilyen hibát minden átnézés átenged, az éles környezetben pedig semmit nem csinál. Ezért egy teszt ellenőrzi, hogy az értékek be vannak állítva, és hogy egyik változó sem használja az aláhúzással elválasztott alakot.
A javítás, 2. rész: minden más stack
A Spring nem az egyetlen keretrendszer, amelynek van készlete, és nem tudunk minden könyvtárat minden nyelven előre beállítani. Ezért a Mythex ügynöke — az AI, amely az appodat írja — most minden stackre érvényes állandó utasítást kap: a publikált appok és adatbázisaik tétlenség esetén elalszanak, ezért egy nyitva tartott kapcsolat a következő kérésre már halott lehet. Ezt kell tennie:
- nem tart nyitva tétlen adatbázis-kapcsolatot, vagy ellenőrzi mindegyiket használat előtt,
- egyszer újrapróbál kapcsolati hiba esetén, és
- a környezetben a platform által biztosított adatbázis-beállításokat használja, nem épít saját készletet a
DATABASE_URLelemzésével.
Az utolsó pont visszakapcsol az 1. részhez: az a app, amely a biztosított beállításokat használja, automatikusan megkapja az alvásbiztos konfigurációt.
Az eredmény
A platformon, ahol a publikált appjainkat futtatjuk, az első kérés az ébredés után 12,7 másodpercről 2,3 másodpercre csökkent.
Amit ebből tanultunk
- Minden rétegnek egyet kell értenie abban, mi marad meg. Egy befagyasztott app és egy alvó adatbázis is ésszerű döntést hozott. Együtt az app olyan állapottal ébredt, amely már nem volt igaz.
- Az állandóan futó szerverekre tervezett alapértelmezések nem illenek a nullára skálázódó appokhoz. A kapcsolatok melegen tartása jó ötlet, amíg minden körülötte ki nem hűl.
- Az adatot a keretrendszer saját formátumában add meg. Egy URL nekünk egyszerű volt, de minden Spring-appot arra kényszerített, hogy kézzel építsen egy készletet, amely figyelmen kívül hagyta a saját konfigurációját.
- Teszteld, hogy a beállítás úgy van-e írva, ahogy a keretrendszer olvassa. Egy helyes érték rossz néven csendben semmit nem csinál.
Ha új vagy abban, hogyan működnek az adatbázisok a Mythexen, lásd az adatbázis-dokumentációt, és a mi az a Postgres magyarázatunkat.