Сайт использует сookies для хранения данных. Продолжая использовать сайт, вы даёте согласие на работу с этими файлами.

ОК
🧱
Данные
Опубликовано:
22.06.2026
Обновлено:
09.07.2026

PgBouncer: пулер соединений для перегруженной базы PostgreSQL

Данил Мануйлов

PgBouncer простыми словами: зачем нужен и как настроить

Представь: приложение работает, трафик растёт. Внезапно PostgreSQL начинает отдавать ошибку FATAL: sorry, too many clients. Сервер не сломан - он просто захлебнулся соединениями. PgBouncer решает эту проблему без переписывания кода и без апгрейда железа.

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

Почему база ломается от соединений

Как PostgreSQL обрабатывает соединения

PostgreSQL устроен просто и прямолинейно: на каждое входящее подключение сервер делает fork() и запускает отдельный процесс - backend process. Пока соединение живо, процесс живёт вместе с ним, занимая память и процессорное время.

Это работает хорошо при десятках соединений. Но современные веб-приложения и микросервисы открывают сотни и тысячи подключений одновременно.

Чем опасен рост max_connections

Первый инстинкт - увеличить max_connections в postgresql.conf. Но это ловушка:

  • Память. Каждое соединение потребляет 5–10 МБ RAM ⚠️ (оценка, зависит от рабочих буферов и нагрузки). 500 соединений → 2,5–5 ГБ только на обслуживание подключений.
  • CPU. Чем больше процессов, тем больше контекстных переключений. Ядра заняты переключением, а не выполнением запросов.
  • Нестабильность. Система сначала тормозит, потом падает - даже при умеренной нагрузке.

Симптомы перегрузки

Понять, что база задыхается от соединений, помогают эти признаки:

  • ошибка FATAL: sorry, too many clients в логах приложения
  • время отклика растёт даже при простых запросах
  • pg_stat_activity показывает десятки «idle» соединений, которые ничего не делают
  • CPU сервера загружен, а запросы медленные

Авторская ремарка: на одном проекте мы столкнулись с этой проблемой при 120 одновременных пользователях. Поднять max_connections до 500 не помогло - только ускорило деградацию. PgBouncer убрал проблему за 40 минут настройки.

Что такое PgBouncer и как он работает

Схема работы: клиент → PgBouncer → PostgreSQL

PgBouncer - лёгкий прокси-пулер, который встаёт между приложением и базой данных. Приложение думает, что подключается к PostgreSQL, но на самом деле соединяется с PgBouncer (порт 6432 по умолчанию).

Приложение (500 клиентов)
↓
PgBouncer :6432
[пул из 30 соединений]
↓
PostgreSQL :5432

Принцип работы:

  1. Клиент подключается к PgBouncer, а не к PostgreSQL напрямую.
  2. PgBouncer проверяет пул - есть ли свободное серверное соединение.
  3. Если есть - отдаёт его клиенту. Если нет - ставит клиента в очередь.
  4. После завершения работы физическое соединение возвращается в пул, а не закрывается.

Результат: PostgreSQL видит 30 соединений вместо 500. Память и CPU под контролем.

Что PgBouncer ускоряет (а что нет)

Важно понять сразу: PgBouncer не ускоряет сами SQL-запросы. Он оптимизирует фазу установления соединений - убирает накладные расходы на fork() и аутентификацию при каждом обращении к базе.

Что реально улучшается:

Что До PgBouncer После
Число процессов PostgreSQL = числу клиентов = размеру пула
Время на connect/disconnect 1–5 мс каждый раз минимальное (переиспользование)
Пиковое потребление RAM пропорционально клиентам контролируемо
Устойчивость при всплесках ошибки при превышении лимита очередь в PgBouncer

PgBouncer vs pgpool-II

⚠️ Предположительно, детальное сравнение производительности требует актуального бенчмарка. Ниже - ключевые структурные отличия по публичной документации:

Критерий PgBouncer pgpool-II
Назначение Только пулинг соединений Пулинг + балансировка нагрузки + репликация
Сложность Низкая Высокая
Потребление ресурсов Минимальное Выше
Поддержка read-replicas Нет Да
Применение OLTP, веб-приложения HA-кластеры, read-heavy нагрузка

Если нужен только пулинг - берите PgBouncer. Если нужна балансировка между мастером и репликами - смотрите в сторону pgpool-II.

Три режима пула: session, transaction, statement

Ключевой параметр PgBouncer - pool_mode. Он определяет, когда серверное соединение возвращается обратно в пул.

session pooling: максимум совместимости

pool_mode = session

Серверное соединение закреплено за клиентом на всю сессию - пока клиент не отключится. Поведение почти идентично прямому подключению к PostgreSQL:

  • работают сессионные prepared statements
  • работают временные таблицы
  • работают SET-параметры на уровне сессии

Минус: пул почти не работает. Если у тебя 200 постоянных соединений от приложения - в PostgreSQL будет ровно 200 соединений. Экономии нет.

Когда использовать: приложения, активно использующие сессионное состояние (долгоживущие prepared statements, временные таблицы).

transaction pooling: лучший баланс

pool_mode = transaction

Серверное соединение выдаётся только на время транзакции (BEGIN ... COMMIT), затем возвращается в пул. Это главный режим для OLTP-нагрузки:

  • 500 клиентов могут работать через 30 серверных соединений
  • пул максимально эффективен

Важный нюанс: сессионное состояние не сохраняется между транзакциями. Это означает:

  • сессионные prepared statements не работают (они могут уйти в другое соединение)
  • SET variable без LOCAL может потеряться
  • временные таблицы ведут себя непредсказуемо

Обязательно: установите server_reset_query = DISCARD ALL - тогда PgBouncer будет очищать состояние соединения перед возвратом в пул.

Когда использовать: большинство современных веб-приложений, микросервисы, Django, FastAPI с ORM.

statement pooling: осторожно

pool_mode = statement

Соединение возвращается в пул после каждого отдельного SQL-запроса. Многозапросные транзакции (BEGIN ... COMMIT) фактически не работают - каждый запрос может попасть в разное соединение.

Используйте только если точно понимаете последствия и все операции - атомарные одиночные запросы без транзакций.

Установка и базовая настройка

Установка на Ubuntu/Debian

sudo apt update
sudo apt install pgbouncer -y

Для получения актуальных версий рекомендуется подключить официальный репозиторий PGDG:

sudo install -d /usr/share/postgresql-common/pgdg
sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \
--fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
sudo sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] \
https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \
> /etc/apt/sources.list.d/pgdg.list'
sudo apt update && sudo apt install pgbouncer -y

Установка на RHEL/CentOS/AlmaLinux

sudo dnf install pgbouncer

Конфиг pgbouncer.ini: ключевые параметры

Основной файл - /etc/pgbouncer/pgbouncer.ini:

[databases]
; * = маршрут для всех баз, или конкретное имя
myapp = host=127.0.0.1 port=5432 dbname=myapp_db

[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 6432

; Аутентификация
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt

; Режим пула
pool_mode = transaction

; Лимиты
max_client_conn = 500
default_pool_size = 50
min_pool_size = 10
reserve_pool_size = 20
reserve_pool_timeout = 5

; Таймауты
server_idle_timeout = 600
server_lifetime = 3600
query_wait_timeout = 120
client_login_timeout = 60

; Сброс состояния между транзакциями (обязателен для transaction-пула)
server_reset_query = DISCARD ALL

; Диагностика
application_name_add_host = 1
log_connections = 1
log_disconnections = 1
stats_period = 60

; Консоль управления
admin_users = pgbouncer

После настройки запустите и добавьте в автозагрузку:

sudo systemctl enable pgbouncer
sudo systemctl start pgbouncer

Проверьте подключение (PgBouncer слушает порт 6432):

psql -h 127.0.0.1 -U myuser -d myapp -p 6432

Аутентификация: scram-sha-256 и md5

По умолчанию PgBouncer работает в режиме trust - без проверки пароля. Для продакшена используйте scram-sha-256 или хотя бы md5.

Файл /etc/pgbouncer/userlist.txt:

"myuser" "SCRAM-SHA-256$<хеш из pg_shadow>"

Хеш пароля берётся прямо из PostgreSQL:

SELECT usename, passwd FROM pg_shadow WHERE usename = 'myuser';

Не забудьте разрешить PgBouncer подключаться в pg_hba.conf PostgreSQL:

host all all PGBOUNCER_IP/32 scram-sha-256

После изменений - перезагрузите оба сервиса.

Расчёт размера пула и таймауты

max_client_conn и default_pool_size

Это два самых важных параметра:

  • max_client_conn - максимум клиентов, которых PgBouncer удерживает одновременно (часть из них может стоять в очереди). По умолчанию 100. Ставьте в 2–3× от числа воркеров приложения.
  • default_pool_size - сколько реальных соединений к PostgreSQL на пару «база + пользователь». Именно этот параметр экономит память на стороне Postgres.

Практические ориентиры:

Размер VDS Воркеры приложения max_client_conn default_pool_size
2 CPU / 4–8 ГБ ~100 300–400 30–50
4–8 CPU / 16–32 ГБ ~300–500 800–1200 60–120

Главное правило: суммарный пул по всем базам и пользователям не должен превышать max_connections в PostgreSQL - иначе Postgres начнёт отказывать в логине.

reserve_pool_size и min_pool_size

  • min_pool_size - «тёплые» соединения, которые PgBouncer держит открытыми заранее. Снижает задержку на первые запросы под нагрузкой.
  • reserve_pool_size - резервные соединения для кратковременных всплесков, когда основной пул исчерпан. Рекомендуется 10–30% от default_pool_size.

Если PgBouncer задействовал резервный пул - это сигнал в логах, что основной default_pool_size стоит увеличить.

Таймауты: query_wait_timeout, server_idle_timeout, server_lifetime

Параметр Зачем Типичное значение
query_wait_timeout Как долго клиент ждёт свободное соединение 60–120 сек
server_idle_timeout Через сколько секунд закрыть простаивающее соединение 600 сек
server_lifetime Мягкая ротация соединений против утечек памяти 3600–7200 сек
client_login_timeout Лимит фазы логина клиента 60 сек
client_idle_timeout Отключать ли пассивных клиентов (0 = нет) 0

Мониторинг: метрики и консоль

Команды SHOW POOLS / SHOW STATS / SHOW CLIENTS

PgBouncer предоставляет административную консоль через псевдобазу pgbouncer:

psql -h 127.0.0.1 -p 6432 -U pgbouncer pgbouncer

Основные команды:

Команда Что показывает
SHOW POOLS; Активные клиенты, очередь, свободные серверные соединения
SHOW STATS; Число запросов, время выполнения, объём трафика
SHOW CLIENTS; Каждый клиент с его статусом и ожиданием
SHOW SERVERS; Реальные соединения к PostgreSQL
SHOW CONFIG; Текущий конфиг с учётом переопределений
RELOAD; Перечитать конфиг без остановки

Сигналы тревоги: cl_waiting и sv_idle

Два ключевых числа из SHOW POOLS:

  • cl_waiting > 0 длительное время - пул слишком мал или запросы слишком долгие. Увеличивайте default_pool_size или оптимизируйте запросы.
  • sv_idle = 0 постоянно - вы на пределе. Сервер PostgreSQL не справляется с текущим пулом.

Авторская ремарка: достаточно добавить алерт в мониторинг на cl_waiting > 5 в течение 30 секунд - это даст время заметить проблему до деградации сервиса.

Reload без даунтайма

PgBouncer поддерживает перезагрузку конфига и онлайн-перезапуск без разрыва клиентских соединений:

# Перезагрузить конфиг
sudo systemctl reload pgbouncer

# Или через консоль
psql -h 127.0.0.1 -p 6432 -U pgbouncer pgbouncer -c "RELOAD;"

# Онлайн-перезапуск процесса (новый процесс принимает соединения от старого)
sudo -u postgres pgbouncer -R /etc/pgbouncer/pgbouncer.ini -d

Перед обслуживанием используйте PAUSE [dbname] - PgBouncer дождётся завершения текущих запросов и приостановит новые подключения.

Типичные ошибки и как их чинить

too many clients

Ошибка: FATAL: too many clients already в логах PgBouncer.

Причина: достигнут max_client_conn - PgBouncer сам задыхается от клиентов.

Решение:

  1. Увеличить max_client_conn.
  2. Найти источник лишних соединений: зависшие воркеры, ORM с агрессивным пулингом, утечки соединений в коде.

Другой вариант: sorry, too many clients уже от самого PostgreSQL - суммарный пул превысил max_connections. Уменьшить default_pool_size или увеличить max_connections с учётом доступной RAM.

prepared statements в transaction-режиме

Ошибка: prepared statement "X" already exists или prepared statement "X" does not exist.

Причина: в transaction-режиме каждая транзакция может получить другое серверное соединение. Сессионные prepared statements теряются или конфликтуют.

Решения:

  • Переключить конкретную базу/пользователя на pool_mode = session.
  • Отключить сессионные prepared statements в приложении (ORM-настройки) или использовать протокольные prepared statements с параметром max_prepared_statements (поддерживается в новых версиях PgBouncer).
  • Убедиться, что server_reset_query = DISCARD ALL выставлен.

Ошибки аутентификации

Ошибка: no pg_hba.conf entry for host "X", user "Y".

Решение: проверить, что IP-адрес PgBouncer добавлен в pg_hba.conf PostgreSQL с правильным методом аутентификации. После изменений перезагрузить PostgreSQL (SELECT pg_reload_conf();).

Альтернативное мнение

Часть разработчиков считает, что PgBouncer - это костыль, а правильное решение - переписать приложение под async-пулинг (например, asyncpg в Python или pgx в Go). У этого подхода есть логика: современные async-фреймворки сами управляют соединениями и не создают idle-сессии. Однако на практике большинство production-систем используют уже работающий синхронный код, Django ORM, Celery-воркеры - и здесь PgBouncer даёт результат за минимум усилий, не требуя переписывания ни строчки кода приложения.

Нетривиальный факт

PgBouncer поддерживает онлайн-перезапуск через передачу файловых дескрипторов от старого процесса к новому (-R флаг). Новый процесс «подхватывает» открытые соединения, а старый завершается без потерь. Эту же механику использует Nginx в своём graceful restart - один из элегантных паттернов Unix-демонов.

Часто задаваемые вопросы (FAQ)

Что такое PgBouncer простыми словами?

PgBouncer - прокси между приложением и PostgreSQL. Он принимает сотни клиентских подключений, но держит к базе только небольшой фиксированный пул соединений. Приложение думает, что подключается к PostgreSQL напрямую - на деле работает через посредника.

Какой pool_mode выбрать?

Начинайте с transaction. Он даёт лучшую утилизацию пула при OLTP-нагрузке. Переходите на session, если приложение активно использует сессионные prepared statements или временные таблицы между транзакциями.

На каком порту работает PgBouncer?

По умолчанию на порту 6432 (PostgreSQL работает на 5432). В конфиге приложения замените порт подключения с 5432 на 6432 - и всё.

Почему в transaction-режиме ломаются prepared statements?

Сессионные prepared statements привязаны к конкретному соединению. В transaction pooling каждая транзакция может получить разное серверное соединение - и statement теряется или конфликтует. Решение: отключить их в приложении или переключить на session pooling для конкретной базы.

Нужно ли менять код приложения?

Нет. Достаточно изменить строку подключения - хост и порт указать PgBouncer вместо PostgreSQL. Приложение продолжает работать без изменений.

Зачем нужен server_reset_query = DISCARD ALL?

В transaction pooling одно соединение обслуживает разных клиентов. Перед возвратом в пул PgBouncer выполняет DISCARD ALL - очищает сессионные параметры, временные объекты, снимает блокировки. Без этого состояние одного клиента может «перетечь» к другому.

Как перезапустить PgBouncer без разрыва соединений?

Используйте sudo systemctl reload pgbouncer для перезагрузки конфига или pgbouncer -R для онлайн-перезапуска процесса - он передаёт открытые соединения новому процессу без разрыва.

Источники

  1. Рег.облако - «Как установить и запустить PgBouncer для PostgreSQL»: https://reg.cloud/blog/pgbouncer-dlya-postgresql/
  2. fastfox.pro - «Пулы соединений PostgreSQL, конфиг, лимиты и метрики»: https://fastfox.pro/blog/tutorials/pgbouncer-postgresql-pooling-guide/
  3. Habr Q&A - «Как pgbouncer обрабатывает idle сессии»: https://qna.habr.com/q/1340768
  4. Cybertec PostgreSQL - «pgbouncer: Types of PostgreSQL connection pooling»: https://www.cybertec-postgresql.com/en/pgbouncer-types-of-postgresql-connection-pooling/
  5. Postgres Professional - Документация pgbouncer: https://postgrespro.ru/docs/postgrespro/current/pgbouncer
  6. Microsoft Azure PostgreSQL - «PgBouncer в гибком сервере»: https://learn.microsoft.com/ru-ru/azure/postgresql/flexible-server/concepts-pgbouncer
  7. Arenadata Docs - «Как работать с PgBouncer»: https://docs.arenadata.io/ru/ADPG/current/concept/architecture/pgbouncer.html
Это авторская статья, основанная на личном опыте и субъективном взгляде автора. Заметили ошибку или битую ссылку? Сообщите нам: info@codesrc.ru - мы оперативно исправим. Спасибо, что помогаете делать блог лучше.
Следите за нами в соцсетях:

Читайте также