Пулеры соединений¶
Пулер в режиме транзакций — PgBouncer с pool_mode = transaction — выдаёт клиенту серверное
соединение на одну транзакцию. Между двумя транзакциями (и между двумя командами вне транзакции)
следующая команда может попасть на другое серверное соединение. Запросы и транзакции hare за таким
пулером работают без изменений; то, что держит собственную сессию, требует настроек ниже.
hare поддерживает PgBouncer 1.22.1 и новее с подготовленными командами между транзакциями
(max_prepared_statements > 0) — оба драйвера сохраняют за ним свой кэш подготовленных команд. PgBouncer
1.21.0–1.22.0 после COPY FROM STDIN (bulk_create(use_copy=True)) теряет учёт подготовленных команд
серверного подключения, и следующая команда на нём падает с unnamed prepared statement does not
exist; в PgBouncer 1.22.1 это исправлено. asyncpg отправляет команду длиннее своего
max_cacheable_statement_size (по умолчанию 15 КБ) безымянной подготовленной командой: готовит её одним
обращением к серверу, а выполняет следующим, — пулер транзакций может выдать для второго другое серверное
подключение, и оно падает с unnamed prepared statement does not exist. За пулером увеличьте
max_cacheable_statement_size подключения для своих длинных команд; собственные команды hare в него
укладываются.
Настройка hare¶
Сообщите hare, что соединение идёт через такой пулер и где находится сам сервер:
postgresql://app:secret@pgbouncer:6432/app?transaction_pooling=true&direct_host=postgres&direct_port=5432
| Параметр | По умолчанию | Что задаёт |
|---|---|---|
transaction_pooling |
false |
Соединение идёт через пулер в режиме транзакций. |
direct_host |
нет | Адрес самого сервера в обход пулера — для работы, которой нужна своя сессия (ниже). Только вместе с transaction_pooling, иначе ConfigurationError. |
direct_port |
port соединения |
Порт самого сервера. Требует direct_host. |
Пользователь, пароль, база и настройки TLS прямого соединения — те же, что у соединения.
Что hare делает иначе¶
При transaction_pooling=true:
LISTEN—NotificationListener, будильникListenNotifyWakeupочереди исходящих событий — открывает соединение наdirect_host.LISTENчерез пулер терял бы уведомления сразу после конца своей транзакции. Безdirect_host—ConfigurationError.- Сессионный тайм-аут блокировки неатомарной миграции (
lock_timeout) ставится на соединении сdirect_host— он не остаётся на серверном соединении, которое пулер отдаст другому клиенту. Безdirect_host—ConfigurationError. - Команда, подготовленный план которой устарел после изменения схемы. PgBouncer делит подготовленную
команду между клиентами по её тексту, поэтому после миграции, которая меняет результат команды
(
ALTER COLUMN ... TYPE), сервер отвергает её с cached plan must not change result type на каждом серверном соединении, где она была подготовлена раньше. hare отправляет команду как есть и отдаёт ошибку сервера: после такой миграции переподключите серверные соединения PgBouncer —RECONNECTв его консоли администратора или перезапуск пула, — чтобы они подготовили команды заново. DROP DATABASEудаляет базуWITH (FORCE)— пулер держит свои сессии к базе открытыми и после ухода клиентов.- Путь поиска опции
schemaи схемы на арендатора: - на PostgreSQL 18+ сервер сообщает пулеру каждое изменение пути поиска, и PgBouncer
(
track_extra_parameters = search_path) восстанавливает путь каждого клиента на серверном подключении, которое ему выдаёт. hare проверяет это один раз при открытии пула: пулер, который не передаёт путь серверу, выполнял бы команды всех арендаторов в одной схеме, поэтому hare вместо этого не стартует сConfigurationError; - PostgreSQL 14–17 не сообщает пулеру путь поиска, и PgBouncer не может его восстановить — клиент
получил бы путь того клиента, который пользовался серверным подключением до него. hare отказывает
такому подключению с
ConfigurationErrorпри открытии пула: опцииschemaи схеме на арендатора за пулером в режиме транзакций нужен PostgreSQL 18+ или подключение напрямую к серверу. - Вход, который отверг пулер (неверный пароль), даёт
ConfigurationError, как и отказ самого сервера, и не повторяется.
Что не требует ничего¶
Не держат сессию дольше своей транзакции и работают за пулером как есть: транзакции и точки сохранения,
арендаторы защиты строк (ставятся на транзакцию),
statement_timeout/lock_timeout у Transactions.atomic() (SET LOCAL), блокировка миграций
(рекомендательная блокировка транзакции), двухфазная фиксация, stream() внутри транзакции,
select_for_update(), COPY и relay очереди исходящих событий.
Настройка, изменённая для базы или роли (ALTER DATABASE ... SET), доходит только до серверных
соединений, которые пулер откроет после неё, — открытые сохраняют старое значение, пока PgBouncer не
переподключит их (RECONNECT в его админ-консоли).
Настройки PgBouncer¶
[pgbouncer]
pool_mode = transaction
; Подготовленные команды между транзакциями — обязательно для hare.
max_prepared_statements = 200
; Нужно с опцией schema или схемой на арендатора на PostgreSQL 18+.
track_extra_parameters = search_path
TimeZone и application_name PgBouncer передаёт сам — часовому поясу сессии hare (UTC) ничего не
нужно.
Проверка здоровья¶
Пинг проверки здоровья идёт через пулер. HealthCheck(check_direct=True) пингует ещё и сам сервер — по
direct_host/direct_port: так видно, когда пулер работает, а сервер нет (Метрики пула и
здоровье). Пул этого прямого клиента в снимке и
метриках пула имеет роль DIRECT.