PgBouncer: какой режим пула выбрать для PostgreSQL
PgBouncer может держать соединение с PostgreSQL на всё время клиентской сессии, только на транзакцию или на один запрос. Выбор влияет не только на число подключений, но и на то, какие возможности PostgreSQL останутся доступны приложению.

PgBouncer может сократить число прямых подключений к PostgreSQL, но один неверно выбранный режим меняет поведение приложения: например, временная таблица или настройка сессии перестанет быть доступна следующему запросу. Разберём три режима PgBouncer 1.23.x — session, transaction и statement — и цену каждого выбора.
Что именно объединяет PgBouncer
Приложение открывает клиентские соединения с PgBouncer, а тот выдаёт им серверные соединения с PostgreSQL из пула. Клиентское соединение может оставаться открытым, пока соответствующее серверное соединение обслуживает другого клиента. Это помогает не создавать отдельный процесс PostgreSQL для каждого кратковременного запроса.
Пул не ускоряет сам SQL-запрос и не добавляет серверу вычислительных ресурсов. Если запросы медленные, а подключений уже немного, PgBouncer не устранит причину. Зато он помогает, когда приложение часто открывает соединения или число подключений резко растёт при всплеске трафика.
Термин. Серверное соединение — соединение между PgBouncer и PostgreSQL. Клиентское — соединение между приложением и PgBouncer. В режиме transaction один клиент в разные моменты может получить разные серверные соединения.
Три режима и цена каждого
В PgBouncer 1.23.x режим выбирают параметром pool_mode. Он определяет, когда PgBouncer возвращает серверное соединение в пул. Чем раньше оно освобождается, тем выше возможность разделять небольшой запас соединений между клиентами — и тем меньше гарантий сохранения состояния сессии.
| Режим | Когда освобождается серверное соединение | Что выигрываете | Чем платите |
|---|---|---|---|
session | Когда клиентское соединение закрывается | Наиболее близкое к прямому подключению поведение: соединение закреплено за клиентом | Серверных соединений нужно больше; короткие запросы не позволяют эффективно делить их между клиентами |
transaction | После завершения транзакции | Серверное соединение можно быстро передать следующему клиенту; обычно это основной кандидат для приложений с короткими независимыми транзакциями | Между транзакциями клиент не владеет тем же соединением PostgreSQL. Состояние сессии и функции, требующие постоянного закрепления, требуют проверки |
statement | После выполнения отдельного SQL-оператора | Максимально короткое закрепление серверного соединения | Транзакция из нескольких операторов не подходит. Приложение должно работать с ограничениями режима на уровне каждого запроса |
Режим пула — не переключатель скорости. Это контракт между приложением и базой: насколько долго приложение вправе считать серверное соединение своим.
Как выбрать режим для проекта
Session: когда важна совместимость
Выбирайте session, если приложение рассчитывает на состояние соединения между запросами: использует команды, привязанные к конкретной сессии PostgreSQL, или держит подключение открытым по архитектурным причинам. Этот режим обычно проще внедрить без изменений приложения, но экономия серверных соединений будет ограниченной: каждый подключённый клиент может удерживать серверное соединение.
Session не гарантирует, что пул сам по себе решит проблему слишком большого числа клиентов. Проверьте, сколько соединений действительно одновременно занято, а не только открыто со стороны приложения.
Transaction: для коротких независимых операций
Transaction часто подходит веб-приложениям и сервисам, где запросы выполняются внутри коротких транзакций, а между ними приложение не рассчитывает сохранить состояние PostgreSQL-сессии. После завершения транзакции серверное соединение возвращается в пул и может обслужить другого клиента.
Перед переходом проверьте, не полагается ли код на состояние соединения между транзакциями: например, на временные таблицы, сессионные блокировки, LISTEN/NOTIFY или настройки, которые приложение устанавливает на уровне сессии. Совместимость конкретных возможностей зависит от способа использования и версии PgBouncer. Сверяйтесь с официальной таблицей возможностей, а не переносите поведение прямого подключения на режим transaction автоматически.
Есть и отдельный нюанс с подготовленными запросами: поддержка зависит от протокола и настроек PgBouncer. Если драйвер активно использует prepared statements, проверьте документацию вашей версии и проведите тест именно с используемым драйвером.
Statement: только если приложение готово к ограничениям
В режиме statement соединение возвращается после каждого SQL-оператора. Это не означает, что любой код станет быстрее: если приложению нужны транзакции из нескольких команд, режим не подойдёт. Его стоит рассматривать только тогда, когда модель запросов действительно состоит из независимых операторов, а ограничения проверены на реальном приложении.
Что проверить до переключения
Главная ошибка — выбрать более агрессивный режим только потому, что он обещает эффективнее делить подключения. Сначала выясните, что приложение делает внутри и между транзакциями. Проверяйте не только успешный ответ на простой SELECT, но и реальные сценарии: авторизацию, фоновые задачи, повторные попытки и обработку ошибок.
- Зафиксируйте текущие ожидания приложения. Найдите код, который открывает транзакции, задаёт параметры сессии, использует временные таблицы или ждёт уведомления. Проверка пройдена, если понятно, какие из этих действий требуют одного и того же соединения.
- Уточните совместимость. Сопоставьте найденные возможности с таблицей PgBouncer для установленной версии и используемого протокола драйвера. Проверка пройдена, если спорные функции проверены тестом, а не предположением.
- Проведите нагрузочный тест с выбранным режимом. Воспроизведите обычные запросы и пики одновременной работы. Проверка пройдена, если нет ошибок из-за потерянного состояния, неожиданных блокировок или роста очереди ожидания.
- Сравните работу пула и PostgreSQL. Посмотрите в административной консоли PgBouncer статистику пулов и сопоставьте её с метриками базы. Проверка пройдена, если вы видите, где образуется ожидание: на стороне свободных соединений, в очереди PgBouncer или уже при выполнении запросов в PostgreSQL.
Пулы, лимиты и очередь ожидания
В настройках PgBouncer размер пула обычно задают через default_pool_size, а режим — через pool_mode. Пул формируется для сочетания базы и пользователя, поэтому значение размера нельзя читать как единый общий лимит всех соединений. Параметр max_client_conn ограничивает число клиентских подключений, но сам по себе не говорит, сколько подключений получит PostgreSQL.
Если клиентам не хватает свободных серверных соединений, они ждут. Это может быть ожидаемым поведением при кратком всплеске. Но постоянная очередь может означать, что пул мал, транзакции слишком длинные или запросы упираются в производительность базы. Простое увеличение размера пула способно ухудшить ситуацию: PostgreSQL получит больше одновременной работы, а не обязательно быстрее её выполнит.
В административной консоли PgBouncer используйте SHOW POOLS и SHOW STATS. В частности, смотрите на активные и ожидающие клиентские соединения, число занятых и свободных серверных соединений и время ожидания. Снимайте показатели во время обычной нагрузки и пика: один снимок не показывает, является ли очередь кратковременной.
Где подход ломается
- Длинная транзакция удерживает серверное соединение. В режиме transaction освобождение происходит после завершения транзакции, а не после каждого запроса приложения. Проверьте транзакции, в которых приложение ждёт внешнюю сеть или пользователя.
- Приложение принимает клиентское соединение за постоянную сессию PostgreSQL. В transaction оно может получить разные серверные соединения в разных транзакциях. Уберите такую зависимость или используйте совместимый режим.
- Увеличили пул, но не проверили базу. Больше серверных соединений может увеличить конкуренцию за ресурсы PostgreSQL. Сравнивайте ожидание в PgBouncer с загрузкой базы и длительностью запросов.
- Проверили только обычные запросы. Ошибки часто проявляются на фоновых задачах, подготовленных запросах и редко используемых путях приложения. Включите их в тест перед переключением.
Следующий шаг: измерьте очередь до изменения режима
Сначала снимите показатели SHOW POOLS и SHOW STATS на обычной и пиковой нагрузке, затем проверьте длительность транзакций и сценарии, зависящие от состояния сессии. Если приложение готово к transaction, изменяйте режим в тестовой среде и сравнивайте очередь, ошибки и время ответа. Инвалидация состояния приложения и подбор размера пула — отдельные задачи; не смешивайте их с выбором режима.
Источники: PgBouncer: Configuration, PgBouncer: Feature matrix
Частые вопросы
Какой режим выбрать для обычного веб-приложения?
Можно ли включить transaction без изменений в приложении?
В чём разница между max_client_conn и default_pool_size?
Почему клиенты ждут, хотя в PostgreSQL ещё есть ресурсы?
Нужно ли всегда увеличивать пул, если растёт очередь?
Подойдёт ли statement, если приложение выполняет только SELECT?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.