Blog

Budzenie baz danych bez martwych połączeń

Opublikowane aplikacje w Mythex, i ich bazy danych, zasypiają, gdy nikt z nich nie korzysta. Gdy aplikacja się budziła, potrafiła trzymać pierwsze żądanie przez 10–12 sekund, bo próbowała ponownie użyć połączeń do bazy, które umarły, gdy wszystko spało. Teraz aplikacjom Spring Boot nadajemy ustawienia bazy bezpieczne po uśpieniu i mówimy agentowi, żeby budował aplikacje każdego stosu w ten sam sposób. Na platformie hostingowej pierwsze żądanie po wybudzeniu skróciło się z 12,7 sekundy do 2,3 sekundy.

Dlaczego aplikacje i bazy zasypiają

Opublikowana aplikacja Mythex działa na maszynie, która zawiesza się po kilku minutach bezczynności, a jej baza danych to bezserwerowy Postgres, który zasypia po pięciu minutach bezczynności i budzi się przy następnym zapytaniu. To utrzymuje cichą aplikację tanią: płacisz za to, co baza faktycznie zużyła, a śpiąca aplikacja nie zużywa niczego na obliczenia. O stronie rozliczeń pisaliśmy w rozliczaniu baz danych za to, czego faktycznie używają.

Haczyk polega na tym, że oba śpią osobno i nie zgadzają się co do tego, czym jest połączenie.

Objaw: wolna pierwsza wizyta

Większość aplikacji serwerowych trzyma pulę połączeń: garstkę otwartych połączeń do bazy, gotowych do użycia, żeby każde żądanie nie płaciło kosztu otwarcia nowego. To dobry projekt dla aplikacji zawsze włączonej.

Oto co się dzieje ze snem:

  1. Aplikacja działa, z kilkoma bezczynnymi połączeniami w puli.
  2. Nikt nie wchodzi. Maszyna aplikacji zawiesza się — zamrożona, z nienaruszoną pulą.
  3. Baza danych zasypia i zrywa swój koniec każdego połączenia.
  4. Przychodzi odwiedzający. Aplikacja budzi się dokładnie taka, jaka była, wciąż trzymając połączenia, o których baza już nie wie.
  5. Pula oddaje jedno z tych połączeń. Musi się dowiedzieć, że jest martwe — przez próbę i czekanie — zanim je porzuci.

W aplikacji Spring Boot walidacja tych martwych połączeń blokowała pierwsze żądanie przez około 10 sekund, zanim kończyło się błędem „Connection is not available”. Dla odwiedzającego strona po prostu się zawieszała, a potem być może pokazywała błąd.

Dlaczego aplikacje Spring dostawały najgorzej

Spring Boot to popularny framework Javy, a domyślnie używa puli połączeń o nazwie HikariCP. Spring potrafi skonfigurować tę pulę z ustawień, w tym tego, ile bezczynnych połączeń trzymać.

Ale Mythex daje każdej aplikacji bazę jako pojedynczą zmienną DATABASE_URL w postaci postgresql://user:pass@host/db. Spring nie czyta tego formatu bezpośrednio. Więc aplikacje Spring zbudowane w Mythex same konstruowały swoją pulę w kodzie, parsując ten URL — a pula zbudowana ręcznie ignoruje wszystkie ustawienia spring.datasource.* Springa. Nawet gdyby ktoś znał właściwe ustawienia puli, nie miały gdzie zadziałać.

Naprawa, część 1: ustawienia, których Spring może użyć

Gdy projekt ma bazę danych, dostaje teraz także zmienne środowiskowe, które Spring czyta natywnie:

  • SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME i SPRING_DATASOURCE_PASSWORD, przekonwertowane z DATABASE_URL (z wymaganym SSL, chyba że URL mówi inaczej).
  • Ustawienia puli, które przetrwają sen:
UstawienieWartośćDlaczego
Minimalna liczba bezczynnych połączeń0Nie trzymaj niczego otwartego między żądaniami, więc nie ma czego unieważnić
Limit czasu bezczynności30 sekundZamykaj nieużywane połączenia szybko
Maksymalny czas życia2 minutyWycofuj każde połączenie, zanim się zestarzeje
Limit czasu połączenia5 sekundNie wstrzymuj żądania długo, jeśli baza wolno odpowiada

Bez trzymania bezczynnych połączeń obudzona aplikacja otwiera jedno świeże połączenie zamiast przedzierać się przez martwe.

Gdy te zmienne są obecne, Spring sam konfiguruje pulę i ustawienia obowiązują. Cokolwiek projekt ustawił sam, zawsze wygrywa; my uzupełniamy tylko braki. Aplikacje niebędące Springiem ignorują te zmienne.

Szczegół, który prawie sprawił, że to nic nie robiło

Spring mapuje zmienne środowiskowe na swoje ustawienia według reguły, którą łatwo źle zrozumieć. Ustawienie minimum-idle trzeba zapisać jako SPRING_DATASOURCE_HIKARI_MINIMUMIDLE — myślniki pominięte, słowa sklejone. Zapisane jako SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE, co wygląda naturalniej, mapuje się na inne, nieistniejące ustawienie (minimum.idle) i jest po cichu ignorowane.

To rodzaj błędu, który przechodzi każdy przegląd i nic nie robi na produkcji. Dlatego test sprawdza zarówno, czy wartości są ustawione, jak i czy żadna zmienna nie używa formy z podkreślnikami zamiast sklejonych słów.

Naprawa, część 2: każdy inny stos

Spring nie jest jedynym frameworkiem z pulą, a nie możemy wstępnie skonfigurować każdej biblioteki w każdym języku. Dlatego agent Mythex — AI, które pisze Twoją aplikację — ma teraz stałą instrukcję dla każdego stosu: opublikowane aplikacje i ich bazy zasypiają, gdy są bezczynne, więc połączenie trzymane otwarte może być martwe przy następnym żądaniu. Powinien:

  • nie trzymać bezczynnych połączeń do bazy otwartych albo sprawdzać każde przed użyciem,
  • ponowić raz przy błędzie połączenia, i
  • używać ustawień bazy, które platforma podaje w środowisku, zamiast budować własną pulę przez parsowanie DATABASE_URL.

Ostatni punkt zamyka pętlę z częścią 1: aplikacja zbudowana na dostarczonych ustawieniach automatycznie dostaje konfigurację bezpieczną po uśpieniu.

Wynik

Zmierzone na platformie hostingowej, na której uruchamiamy opublikowane aplikacje, pierwsze żądanie po wybudzeniu skróciło się z 12,7 sekundy do 2,3 sekundy.

Co z tego wynieśliśmy

  • Każda warstwa, która zasypia, musi zgadzać się co do tego, co przetrwa. Zamrożona aplikacja i uśpiona baza podjęły każda rozsądną decyzję. Razem aplikacja obudziła się z stanem, który nie był już prawdziwy.
  • Domyślne ustawienia zaprojektowane dla serwerów zawsze włączonych nie pasują do aplikacji skalujących się do zera. Utrzymywanie połączeń w cieple to dobry pomysł, dopóki wszystko wokół nie zimnieje.
  • Dawaj frameworkom ich dane w ich własnym formacie. Jeden URL był dla nas prosty, ale zmuszał każdą aplikację Spring do ręcznego budowania puli, która ignorowała jej własną konfigurację.
  • Testuj, czy ustawienie jest zapisane tak, jak framework je czyta. Poprawna wartość pod złą nazwą nie robi nic, po cichu.

Jeśli dopiero poznajesz, jak bazy danych działają w Mythex, zobacz dokumentację baz danych i nasze wyjaśnienie czym jest Postgres.

Mythex · Pricing · Zbuduj wszystko z AI · Szablony stron i aplikacji · Mythex w porównaniu · Słownik budowania aplikacji z AI · Darmowe narzędzia do budowania aplikacji z AI · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)