Блог

Пробуждение баз данных без мёртвых соединений

Опубликованные приложения в Mythex и их базы данных засыпают, когда ими никто не пользуется. Когда приложение просыпалось, его первый запрос мог висеть 10–12 секунд, потому что приложение пыталось переиспользовать соединения с базой, которые умерли, пока всё спало. Теперь мы даём приложениям на Spring Boot настройки базы, устойчивые ко сну, и просим агента строить приложения на любом стеке так же. На платформе хостинга время первого запроса после пробуждения сократилось с 12,7 секунды до 2,3 секунды.

Почему приложения и базы засыпают

Опубликованное приложение Mythex работает на машине, которая приостанавливается после нескольких минут простоя, а его база данных — это бессерверный Postgres, который засыпает после пяти минут простоя и просыпается по следующему запросу. Именно это делает тихое приложение дешёвым: вы платите за то, что база фактически использовала, а спящее приложение не тратит ресурсы на вычисления. Об оплате мы писали в статье оплата баз данных за то, что они реально используют.

Проблема в том, что эти два компонента засыпают по отдельности и по-разному понимают, что такое соединение.

Симптом: медленный первый визит

Большинство серверных приложений держат пул соединений: несколько открытых соединений с базой, которые ждут наготове, чтобы каждый запрос не платил за открытие нового. Для приложения, которое всегда работает, это правильная схема.

Вот что происходит со сном:

  1. Приложение работает, в пуле несколько простаивающих соединений.
  2. Никто не заходит. Машина приложения приостанавливается — замирает со своим пулом.
  3. База данных засыпает и разрывает свою сторону каждого соединения.
  4. Приходит посетитель. Приложение просыпается ровно в том состоянии, в каком было, всё ещё держа соединения, о которых база уже не знает.
  5. Пул выдаёт одно из этих соединений. Чтобы понять, что оно мёртвое, нужно его попробовать и дождаться — и только потом отказаться от него.

В приложении Spring Boot проверка мёртвых соединений блокировала первый запрос примерно на 10 секунд, после чего тот падал с ошибкой «Connection is not available». Для посетителя сайт просто зависал, а потом, возможно, показывал ошибку.

Почему хуже всего пришлось Spring-приложениям

Spring Boot — популярный Java-фреймворк, и по умолчанию он использует пул соединений HikariCP. Spring может настраивать этот пул через параметры, в том числе задавая, сколько простаивающих соединений держать.

Но Mythex выдаёт каждому приложению базу данных в виде одной переменной DATABASE_URL вида postgresql://user:pass@host/db. Spring не может напрямую прочитать этот формат. Поэтому Spring-приложения на Mythex создавали свой пул прямо в коде, разбирая этот URL, а пул, собранный вручную, игнорирует все настройки spring.datasource.*. Даже если бы кто-то знал правильные настройки пула, применить их было бы негде.

Исправление, часть 1: настройки, которые понимает Spring

Теперь, когда у проекта есть база, мы также выдаём переменные окружения, которые Spring читает нативно:

  • SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME и SPRING_DATASOURCE_PASSWORD, полученные из DATABASE_URL (с обязательным SSL, если в URL не сказано иное).
  • Настройки пула, которые переживают сон:
НастройкаЗначениеПочему
Минимум простаивающих соединений0Между запросами ничего не держать открытым, поэтому нечему устаревать
Тайм-аут простоя30 секундБыстро закрывать неиспользуемые соединения
Максимальное время жизни2 минутыЗакрывать каждое соединение, прежде чем оно состарится
Тайм-аут соединения5 секундНе держать запрос долго, если база медленно отвечает

Поскольку простаивающих соединений не держится, проснувшееся приложение открывает одно новое соединение, а не перебирает мёртвые.

Когда эти переменные есть, Spring сам настраивает пул, и настройки применяются. Всё, что проект задал сам, всегда побеждает; мы заполняем только то, чего не хватает. Не-Spring приложения эти переменные игнорируют.

Деталь, из-за которой всё почти не сработало

Spring сопоставляет переменные окружения с настройками по правилу, которое легко перепутать. Настройку minimum-idle нужно записывать как SPRING_DATASOURCE_HIKARI_MINIMUMIDLE — дефисы убираются, слова слитно. Если записать её как SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE, что выглядит естественнее, она сопоставится с другой, несуществующей настройкой (minimum.idle) и будет тихо проигнорирована.

Такая ошибка проходит любую проверку и ничего не меняет в продакшене. Поэтому тест проверяет и то, что значения заданы, и то, что ни одна переменная не записана в форме с подчёркиваниями.

Исправление, часть 2: все остальные стеки

Spring — не единственный фреймворк с пулом, и мы не можем заранее настроить каждую библиотеку на каждом языке. Поэтому AI-агент Mythex, который пишет ваше приложение, теперь получает постоянную инструкцию для любого стека: опубликованные приложения и их базы засыпают при простое, поэтому соединение, которое было открыто, на следующем запросе может оказаться мёртвым. Агент должен:

  • не держать открытыми простаивающие соединения с базой или проверять каждое перед использованием,
  • однократно повторять запрос при ошибке соединения и
  • использовать настройки базы, которые платформа передаёт в окружении, а не создавать собственный пул, разбирая DATABASE_URL.

Последний пункт замыкает цикл с частью 1: приложение, построенное на предоставленных настройках, автоматически получает конфигурацию, устойчивую ко сну.

Результат

По измерениям на платформе хостинга, где мы запускаем опубликованные приложения, время первого запроса после пробуждения сократилось с 12,7 секунды до 2,3 секунды.

Что мы из этого вынесли

  • Каждый слой, который засыпает, должен соглашаться, что переживёт сон. Замёрзшее приложение и спящая база каждая сделали разумный выбор. Вместе же приложение проснулось, держа состояние, которое уже не соответствовало действительности.
  • Значения по умолчанию, рассчитанные на серверы, которые всегда работают, не подходят приложениям, которые масштабируются до нуля. Держать соединения тёплыми — хорошая идея, пока всё вокруг них не остыло.
  • Отдавайте фреймворкам данные в их собственном формате. Один URL был простым для нас, но заставлял каждое Spring-приложение вручную собирать пул, который игнорировал собственную конфигурацию.
  • Проверяйте, что настройка записана так, как её читает фреймворк. Правильное значение под неправильным именем ничего не делает — и никак об этом не сообщает.

Если вы впервые работаете с базами данных в Mythex, см. документацию по базам данных и наше объяснение что такое Postgres.

Mythex · Pricing · Создавайте что угодно с ИИ · Шаблоны сайтов и приложений · Сравнения Mythex · Глоссарий по созданию приложений с ИИ · Бесплатные инструменты для создания приложений с ИИ · 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 ਪੰਜਾਬੀ Polski 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 简体中文 繁體中文(香港) 繁體中文(台灣)