Что такое connection pooling и зачем он нужен? Чем PgBouncer отличается от Pgpool? Чем session/transaction/statement pooling отличаются?
Connection pooling переиспользует ограниченный набор реальных backend-процессов PostgreSQL. PgBouncer — лёгкий пулер без лишних функций; Pgpool-II добавляет routing и репликацию. Режимы: session сохраняет state сессии, transaction — самый эффективный, statement — почти не используется.
Зачем нужен connection pooling
Каждое соединение с PostgreSQL — отдельный backend-процесс (~5–10 МБ RSS). При 1000 одновременных клиентах это 5–10 ГБ только на процессы, плюс затраты на context switch. Параметр max_connections ограничивает число backend'ов; превышение возвращает ошибку FATAL: sorry, too many clients already. Пулер принимает тысячи клиентских соединений, но держит к PostgreSQL небольшой набор server connections.
PgBouncer vs Pgpool-II
- PgBouncer: легковесный однофункциональный пулер (C, ~1 МБ RSS). Умеет только pooling. Конфигурируется через
pgbouncer.ini; ключевые параметры:pool_mode,max_client_conn,default_pool_size,server_reset_query. Стандартный выбор для web workload. - Pgpool-II: многофункциональный прокси — pooling + load balancing read replicas + online recovery + watchdog HA. Значительно сложнее в настройке; оправдан при нужде в routing между primary/replica или встроенном failover.
Три режима pooling
Session pooling
Server connection закрепляется за клиентом на время всей сессии и возвращается в пул только при disconnect. Сохраняет всё session-local state: temp tables, prepared statements, SET-переменные, advisory locks. Коэффициент мультиплексирования минимален — пул помогает только ограничить пиковое число backend'ов.
Transaction pooling
Server connection возвращается в пул после каждого COMMIT или ROLLBACK. Позволяет держать N server connections для M >> N клиентов. Это наиболее производительный режим, но ломает session-level state: prepared statements, temp tables, SET LOCAL, advisory locks не сохраняются между транзакциями. Требует аудита приложения.
Statement pooling
Server connection возвращается в пул после каждого отдельного SQL-выражения. Запрещает multi-statement транзакции — практически не используется в реальных приложениях.
# /etc/pgbouncer/pgbouncer.ini
[databases]
myapp = host=127.0.0.1 port=5432 dbname=myapp
[pgbouncer]
listen_port = 6432
listen_addr = 0.0.0.0
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 2000
default_pool_size = 25
reserve_pool_size = 5
reserve_pool_timeout = 3
server_reset_query = DISCARD ALL
server_check_query = SELECT 1
log_connections = 0
log_disconnections = 0
Мониторинг состояния пула через псевдо-базу pgbouncer:
-- подключиться: psql -p 6432 pgbouncer
SHOW POOLS;
SHOW STATS;
SHOW CLIENTS;
Подводные камни
- Transaction pooling + prepared statements = intermittent
ERROR: prepared statement does not exist. Отключают server-side prepare в драйвере (например, в asyncpg:statement_cache_size=0; в psycopg3:prepare_threshold=None). SET search_path,SET TimeZoneи другие сессионные параметры не сохраняются между транзакциями в transaction mode;server_reset_query = DISCARD ALLобнуляет state при возврате соединения в пул.- Advisory locks привязаны к server connection, а не к клиенту — в transaction mode lock может «потеряться».
- Пулер не ускоряет медленные запросы; он лишь защищает от connection storm. Если все 25 server connections заняты долгими запросами, клиенты встают в очередь.
- Head-of-line blocking: один медленный запрос блокирует весь пул при маленьком
default_pool_size. - TLS между приложением и PgBouncer и между PgBouncer и PostgreSQL конфигурируются отдельно; часто забывают внутренний сегмент.
- PgBouncer не поддерживает
LISTEN/NOTIFYв transaction mode — соединения для подписки нужно выносить мимо пулера. - При выборе
default_pool_sizeориентируйся на количество CPU PostgreSQL-сервера: эмпирическое правило — 2–4 × vCPU.
Common mistakes
- Считать pooling ускорителем любого запроса.
- Включать transaction mode без проверки ORM.
- Путать PgBouncer и Pgpool по назначению.
What the interviewer is testing
- Просит объяснить session/transaction modes.
- Проверяет prepared statements и temp tables.
- Уточняет sizing пула.