Как управлять пулом соединений к базе данных в Spring и Hibernate
Что проверяют
Понимаете ли вы, что пул соединений в Spring Boot это HikariCP, а Hibernate лишь берёт соединения из готового DataSource. Интервьюер хочет услышать про размер пула, таймауты и то, что держит соединения дольше нужного. Следом спрашивают, откуда ошибка Connection is not available, request timed out.
Как отвечать
Начиная со Spring Boot 2.0 HikariCP стоит по умолчанию, настройки задаются префиксом spring.datasource.hikari.*:
maximum-pool-size: по умолчанию 10. Больше не значит быстрее: у базы ограничены ядра и диски, лишние соединения только ждут друг друга. Сумма пулов всех экземпляров сервиса должна помещаться вmax_connectionsбазы;minimum-idle: по умолчанию равен максимуму, и авторы Hikari советуют так и оставить: пул фиксированного размера ведёт себя стабильнее;connection-timeout: сколько поток ждёт свободное соединение, по умолчанию 30 секунд;max-lifetime: по умолчанию 30 минут. Ставят на несколько секунд меньше таймаутов базы, балансировщика или файрвола, иначе пул выдаст уже разорванное соединение;leak-detection-threshold: пишет в лог стек, если соединение не вернули за заданное время.
Со стороны Hibernate важно, сколько живёт соединение. Оно занято на всю транзакцию @Transactional, поэтому внутри неё не делают HTTP-вызовы и долгие вычисления. Параметр spring.jpa.open-in-view включён по умолчанию, и сессия с соединением может держаться до конца обработки HTTP-запроса. Spring Boot предупреждает об этом в логе при старте, в REST-сервисах его обычно выключают.
Мониторинг: метрики hikaricp.connections.active и hikaricp.connections.pending через Micrometer и Actuator. Если растёт pending при полностью занятом пуле, соединения держатся слишком долго.
Где спотыкаются
Ставят пул на 100 соединений «на всякий случай». При пяти экземплярах сервиса это 500 соединений, и база начинает отказывать.
Настраивают hibernate.connection.pool_size, думая, что меняют Hikari. Это встроенный пул Hibernate, для продакшена он не предназначен.
Прописывают устаревший диалект вроде MySQL5Dialect. В Hibernate 6 диалект определяется автоматически, явное указание обычно не нужно.