open atlas
↑ К треку
Базы данных DB · 05 · 02

Режимы PgBouncer: session, transaction и statement

Transaction mode даёт мультиплексирование 10–100×, но ломает SET, LISTEN, SQL PREPARE и session-level advisory locks; у каждого есть безопасный эквивалент для transaction mode.

DB Middle ◷ 12 min
Уровень
ОсновыJuniorMiddleSenior

Команда переключает PgBouncer с session на transaction mode. Задеплоенный SET search_path = 'app, public' перестаёт работать. Приложение в продакшне шесть месяцев. Ничего не менялось — кроме режима pooler.

Три режима PgBouncer

Выбор неправильного режима — источник большинства инцидентов при миграции на PgBouncer: именно режим определяет, какое состояние сессии сохраняется, и, следовательно, что приложению разрешено делать. Когда настраиваешь PgBouncer, это единственное решение, которое определяет все остальные.

Session mode: backend арендуется клиенту на всё время его соединения. PgBouncer по сути брокер соединений — 1:1 между клиентскими и backend-соединениями. Всё работает: SET, LISTEN, temp tables, session-level advisory locks, классический SQL PREPARE. Мультиплексирование нулевое; выигрыш только в auth offload и очереди.

Transaction mode: backend арендуется только на время одной транзакции (BEGIN…COMMIT, или один autocommit-запрос). Между транзакциями backend возвращается в пул и может перейти к другому клиенту. Именно этот режим даёт реальное мультиплексирование — 10 000-клиентское приложение работает на 20–50 backend. Цена: session state не сохраняется между транзакциями.

Statement mode: backend возвращается после каждого отдельного оператора. Транзакции из нескольких операторов запрещены. Применяется почти исключительно для PL/Proxy-style шардинга; не режим общего назначения.

Продакшн-дефолт — transaction mode: session mode отдаёт весь выигрыш от мультиплексирования; statement mode слишком ограничен для OLTP.

ФункциональностьSession modeTransaction modeФикс в transaction mode
Коэффициент мультиплексированияНет (1:1)10–100×
SET search_path при connectРаботаетТеряется после первой транзакцииALTER ROLE app SET search_path = …
SET LOCAL внутри транзакцииРаботаетРаботает (в рамках той транзакции)
LISTEN / NOTIFYРаботаетСломано — NOTIFY попадает на другой backendОтдельное session-mode соединение для LISTEN
SQL-уровень PREPARE name AS …РаботаетEXECUTE попадает на другой backendProtocol-level prepared statements (драйвер); PgBouncer 1.21+ обрабатывает их
pg_advisory_lock() session-levelРаботаетLock принадлежит тому backend, который обработал вызовpg_advisory_xact_lock() (transaction-level)
Temp tablesРаботаетМогут не сохраниться до следующей транзакцииON COMMIT DROP или перевести в обычную таблицу

Почему SET ломается в transaction mode

В session mode соединение клиента всегда привязано к одному backend. SET search_path = 'app, public' при старте выполняется на backend B1 и остаётся там навсегда.

В transaction mode PgBouncer возвращает B1 в пул после первого COMMIT. Следующий запрос от того же клиента может попасть на B2, который никогда не видел этот SET. Настройка невидима — молча исчезла.

Фикс: ALTER ROLE app SET search_path = 'app, public' — Postgres применяет это к каждому новому соединению для этой роли, поэтому каждый backend стартует с правильной настройкой независимо от того, какой именно был назначен.

Почему LISTEN ломается, и фикс через отдельное соединение

LISTEN channel регистрирует текущий backend для получения NOTIFY channel сообщений. В session mode backend постоянный — события поступают надёжно. В transaction mode backend возвращается в пул между транзакциями. NOTIFY попадает на тот backend, который выбирает Postgres, — он может обслуживать другого клиента; исходный listener никогда не получит событие.

Фикс: открываем одно выделенное соединение, которое обходит PgBouncer или использует session mode исключительно для LISTEN. Весь OLTP остаётся на transaction-mode пуле. Две connection string сосуществуют.

Почему это работает

Зачем в PgBouncer вообще есть session mode? Для команд, мигрирующих постепенно, и для приложений, которым genuinely нужна session-семантика (legacy PREPARE, session advisory locks, долгоживущие temp tables). Session mode — безопасный дефолт; transaction mode — апгрейд производительности, требующий предварительного аудита приложения.

Сравнение режимов PgBouncer
Session mode: мультиплексирование
Нет (1:1)
Transaction mode: мультиплексирование
10–100×
Statement mode: применение
Только PL/Proxy шардинг
Default pool_size
20
Default max_client_conn
100
Память PgBouncer на pooled conn
~2 КБ
Память backend Postgres
~5–10 МБ
Prepared statements в tx mode
PgBouncer 1.21+
Викторина

Команда переключает PgBouncer с session на transaction mode, и `SET search_path = 'app, public'` при connect перестаёт работать. Почему?

Викторина

Лучший вариант, если приложению на PgBouncer transaction mode нужен LISTEN/NOTIFY для инвалидации кеша?

Расставь шаги по порядку

Упорядочи задачи при переходе на transaction mode PgBouncer — от наибольшего к наименьшему приоритету:

  1. 1 Аудит SET (не SET LOCAL) — мигрировать на ALTER ROLE или SET LOCAL
  2. 2 Аудит классических SQL PREPARE — перейти на protocol-level (через драйвер)
  3. 3 Аудит LISTEN — изолировать на выделенном session-mode соединении
  4. 4 Аудит pg_advisory_lock (session-level) — переключить на pg_advisory_xact_lock
  5. 5 Включить max_prepared_statements 1000 (PgBouncer 1.21+) для protocol prepares
  6. 6 Установить server_reset_query = DISCARD ALL при риске утечки состояния
  7. 7 Установить idle_in_transaction_session_timeout в Postgres GUC как safety net
Вспомните перед уходом
  1. 01
    Объясни, что меняется при переходе с session mode на transaction mode в PgBouncer — что работает, что ломается, что становится возможным.
  2. 02
    Почему LISTEN ломается в transaction mode PgBouncer и каков правильный архитектурный фикс?
  3. 03
    Что делает server_reset_query = DISCARD ALL в PgBouncer и когда это необходимо?
Итог

PgBouncer предлагает три режима: session (1:1, нулевое мультиплексирование, всё работает), transaction (мультиплексирование 10–100×, требует аудита приложения) и statement (только для шардинг-прокси). Transaction mode — продакшн-стандарт. Он ломает четыре паттерна — SET вне транзакции (фикс: ALTER ROLE), LISTEN (фикс: выделенное session-mode соединение), SQL-уровень PREPARE (фикс: protocol-level через драйвер, PgBouncer 1.21+) и session-level advisory locks (фикс: pg_advisory_xact_lock). У каждой поломки есть точный эквивалент, безопасный в transaction mode; ни одна функциональность не теряется — только переносится. Теперь, когда после изменения конфига пулера SET перестаёт работать или LISTEN молча теряет события, первая проверка — был ли переход на transaction mode без завершения аудита.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 5 завершено
Связанные уроки
встречается в287

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.