Архитектура пулов

У нас есть два принципиально разных места, где можно расположить пул соединений: внутри самого приложения (Client-side) или перед базой данных (Proxy-side).

1. На стороне приложения

Пул живет прямо в оперативной памяти твоего сервиса. Самый популярный и быстрый пример в мире Java — HikariCP.

  • Зачем нужен: Чтобы потоки внутри твоего приложения не блокировались в ожидании TCP-подключения к сети. Они мгновенно берут коннект из локальной памяти.
  • Проблема: Если у тебя 50 подов микросервиса в Kubernetes, и в каждом HikariCP держит по 20 соединений, то база данных получит 1000 открытых подключений и ей может быть тяжко.
2. На стороне инфраструктуры

Пул живет на отдельном сервере, который стоит «щитом» перед БД. Примеры: PgBouncer, Odyssey (от Яндекса), AWS RDS Proxy.

  • Зачем нужен: Защитить БД. Приложения стучатся в PgBouncer, думая, что это база. PgBouncer принимает тысячи легковесных входящих соединений, но держит с реальным Postgres всего 50-100 физических коннектов, мастерски перекидывая запросы между ними.

Иногда в микросервисной архитектуре используют оба пула одновременно. HikariCP мультиплексирует потоки приложения в сетевые вызовы, а PgBouncer мультиплексирует сетевые вызовы в реальные процессы базы данных.

Режимы работы внешнего пула

Посмотрим на примере PgBouncer.

Внешние пулеры могут жонглировать соединениями по-разному. Это важно понимать при настройке системы:

Режим пулинга Как работает Особенности
Session Pooling Реальное серверное соединение привязывается к клиенту на всё время жизни его сессии. Самый безопасный, поддерживает все фичи БД. Но неэффективен для тысяч микросервисов.
Transaction Pooling Соединение выдается клиенту только на время одной транзакции (BEGIN ... COMMIT), затем сразу отдается другому. Выжимает абсолютный максимум производительности. Минус: ломает работу Prepared Statements и временных таблиц.
Statement Pooling Соединение отдается строго на один SQL-запрос. Ломает транзакции с несколькими запросами. Используется редко (например, при AUTOCOMMIT).

Резюме: Если ты пишешь на Java/Go/Python — обязательно настраивай локальный пул (ограничивай max_connections). Если система растет до десятков инстансов — ставь перед БД PgBouncer в режиме Transaction Pooling, предварительно отключив Prepared Statements в драйвере приложения.

Материалы для глубокого погружения