github ozontech/pg_doorman v3.9.1

5 hours ago

Per-pool PostgreSQL startup parameters

pg_doorman can now inject configured PostgreSQL GUCs into backend StartupMessages. Values apply in three layers:

  • general.startup_parameters
  • pools.<name>.startup_parameters
  • optional startup_parameters returned by passthrough auth_query

This lets one pool set values such as plan_cache_mode, statement_timeout, work_mem, or idle_in_transaction_session_timeout without changing postgresql.conf, ALTER ROLE, or ALTER DATABASE.

PostgreSQL stores these values as session reset defaults, so client-side RESET ALL and DISCARD ALL return to the configured value.

Reloads that change startup parameters recycle affected pools. PostgreSQL-side rejection is returned to the client as PostgreSQL's original ErrorResponse. SHOW STARTUP_PARAMETERS, pool details in the operator console, and Prometheus counters expose the resolved values and rejection counters.

See PostgreSQL startup parameters.

Built-in operator console

pg_doorman now ships a built-in diagnostic console on the /metrics listener. Enable it with [web].ui = true and a non-default admin_password.

The old [prometheus] config section has been renamed to [web]: /metrics and the optional UI now share the same listener settings. [prometheus] is still accepted as a compatibility alias, but it is deprecated and will be removed soon.

The console turns the admin protocol and Prometheus surface into live operator views:

  • Pool, client, server, database, user, app, socket, auth_query, pool scaling, and coordinator state.
  • Live latency, qps, error-rate, and connection-saturation charts.
  • SQLSTATE breakdowns per pool and top error sources.
  • Stuck-query views by current_query_age_ms.
  • Prepared-statement and query-interner views, including top prepared statements and text lookup.
  • Process memory split by category, cgroup limits, thread count, file descriptors, and per-worker CPU.
  • Live log tail for incident debugging.

Admin actions are deliberately narrow and match the admin protocol: Pause, Resume, Reconnect, and Reload. The console is read-only unless the user has admin access. Deployments that need SSO can use JWT authentication alongside Basic auth.

See Web UI.

Prepared-statement cache and query interner

pg_doorman now gives anonymous prepared statements the same plan-cache benefit that named statements already had in transaction pooling. Many drivers send short parameterized queries as Parse with an empty statement name. PostgreSQL treats that as anonymous: the plan lives only until the next anonymous Parse, so without a pooler-side remap the backend repeats planner work on every Bind.

On every anonymous Parse, pg_doorman hashes the query text plus parameter type OIDs, looks up the hash in the pool-level cache, and rewrites the backend-side statement name to an internal DOORMAN_<N>. The client still sees empty statement names; the rewrite exists only between pg_doorman and PostgreSQL. If the current backend already has that DOORMAN_<N> prepared, pg_doorman can synthesize ParseComplete and skip the extra PostgreSQL round-trip.

The cache now has explicit layers:

  • pool-level shared cache, sized by prepared_statements_cache_size (default 8192); 0 disables anonymous remap entirely;
  • per-backend cache, sized by server_prepared_statements_cache_size (inherits prepared_statements_cache_size by default);
  • per-client cache split into Named and Anonymous parts. Named statements remain unbounded. Anonymous statements use an LRU bounded by client_anonymous_prepared_cache_size (inherits prepared_statements_cache_size; 0 means unlimited).

The query interner is also split into NAMED and ANON storage. Anonymous entries now have an idle TTL by default: query_interner_anon_idle_ttl_seconds = 60. Set it to 0 to keep the old unbounded behavior. If both the interner and the pool/client caches drop an anonymous entry before the next Bind, pg_doorman returns SQLSTATE 26000, matching PostgreSQL's native "unnamed prepared statement does not exist" behavior.

This is most useful for OLTP workloads with repeated query shapes and drivers that use anonymous prepared statements by default (lib/pq, libpq PQexecParams, parts of pgjdbc and psycopg). It does not help ad-hoc or OLAP traffic where every query is unique; for those pools, disabling the remap with prepared_statements_cache_size = 0 may be better.

New diagnostics: SHOW INTERNER, SHOW INTERNER N, RESET INTERNER, a kind column in SHOW PREPARED_STATEMENTS, new SHOW POOLS_MEMORY fields, and Prometheus metrics for interner entries, bytes, evictions, synthetic misses, and GC duration. Watch pg_doorman_servers_prepared_hits, pg_doorman_servers_prepared_misses, and pg_doorman_clients_prepared_anonymous_evictions_total to see whether the cache is helping or just churning.

See Anonymous Parse Caching.

Full changelog: https://ozontech.github.io/pg_doorman/changelog.html


Параметры запуска PostgreSQL на уровне пула

pg_doorman теперь умеет задавать параметры PostgreSQL для серверных соединений пула. Он добавляет GUC в StartupMessage, поэтому не нужно менять postgresql.conf, ALTER ROLE или ALTER DATABASE.

Значения собираются из трёх уровней. Более узкий уровень переопределяет предыдущий:

  • general.startup_parameters;
  • pools.<name>.startup_parameters;
  • необязательная колонка startup_parameters из passthrough auth_query.

Так можно настроить для отдельного пула, например, plan_cache_mode, statement_timeout, work_mem или idle_in_transaction_session_timeout, не затрагивая остальные подключения под той же ролью или к той же базе.

PostgreSQL сохраняет эти параметры как значения по умолчанию для сессии. После RESET ALL и DISCARD ALL клиент снова получает значения из pg_doorman, а не исходные значения PostgreSQL.

Если RELOAD меняет startup_parameters, pg_doorman пересоздаёт затронутые пулы. Если PostgreSQL отклоняет параметр при открытии серверного соединения, клиент получает исходный ErrorResponse без переписывания. SHOW STARTUP_PARAMETERS, сведения о пуле в операторской консоли и Prometheus-счётчики показывают итоговые значения и ошибки применения.

См. Параметры запуска PostgreSQL.

Встроенная операторская консоль

pg_doorman теперь поставляет встроенную диагностическую консоль на том же HTTP-сервере, что и /metrics. Она включается через [web].ui = true и требует сменить admin_password с значения по умолчанию.

Секция [web] — новое имя прежней секции [prometheus]: в ней теперь настраиваются и /metrics, и веб-консоль. [prometheus] пока принимается как старое имя для совместимости, но уже считается устаревшей и скоро будет удалена.

Консоль превращает admin protocol и Prometheus-метрики в живые операторские представления:

  • состояние пулов, клиентов, серверов PostgreSQL, баз, пользователей, приложений, сокетов, auth_query, масштабирования пулов и координатора;
  • графики задержек, qps, частоты ошибок и заполненности соединений;
  • разбивка ошибок по SQLSTATE и основные источники ошибок;
  • представления для долгих и зависших запросов по current_query_age_ms;
  • представления для prepared statements и query interner, включая самые активные prepared statements и просмотр текста запроса;
  • память процесса по категориям, лимиты cgroup, количество потоков, файловые дескрипторы и загрузка рабочих потоков;
  • просмотр последних строк лога в реальном времени для разбора инцидентов;

Административные действия намеренно ограничены и совпадают с admin protocol: Pause, Resume, Reconnect и Reload. Без прав администратора консоль остаётся read-only. Если нужен SSO, консоль может принимать JWT наряду с Basic auth.

См. Веб-консоль.

Кэш prepared statements и query interner

pg_doorman теперь даёт анонимным prepared statements тот же выигрыш от кеширования плана, который уже был у именованных statements в transaction pooling. Многие драйверы отправляют короткие параметризованные запросы как Parse с пустым именем statement. Для PostgreSQL это анонимное выражение: план живёт только до следующего анонимного Parse, поэтому без подмены на стороне пулера backend заново запускает планировщик на каждом Bind.

На каждый анонимный Parse pg_doorman считает хеш по тексту запроса и OID типов параметров, ищет его в общем кеше пула и переписывает имя statement на служебное DOORMAN_<N> на стороне PostgreSQL. Клиент по-прежнему видит пустое имя; подмена существует только между pg_doorman и PostgreSQL. Если текущий backend уже держит нужный DOORMAN_<N>, pg_doorman может сам вернуть ParseComplete и не делать лишний round-trip в PostgreSQL.

Кеш теперь явно разделён на уровни:

  • общий кеш пула, размер задаётся prepared_statements_cache_size (по умолчанию 8192); значение 0 полностью отключает подмену анонимных statements;
  • кеш на каждом backend-соединении, размер задаётся server_prepared_statements_cache_size (по умолчанию наследует prepared_statements_cache_size);
  • клиентский кеш разделён на именованную и анонимную части. Именованные statements остаются без лимита. Анонимные statements используют LRU, ограниченный client_anonymous_prepared_cache_size (по умолчанию наследует prepared_statements_cache_size; значение 0 означает без лимита).

Query interner тоже разделён на хранилища NAMED и ANON. Для анонимных записей теперь по умолчанию действует TTL бездействия: query_interner_anon_idle_ttl_seconds = 60. Значение 0 возвращает прежнее поведение без ограничения по времени. Если interner и кеши пула/клиента успели удалить анонимную запись до следующего Bind, pg_doorman возвращает SQLSTATE 26000, как обычный PostgreSQL для ошибки "unnamed prepared statement does not exist".

Больше всего это помогает OLTP-нагрузкам с повторяющимися формами запросов и драйверам, которые по умолчанию используют анонимные prepared statements (lib/pq, libpq PQexecParams, часть режимов pgjdbc и psycopg). Для ad-hoc или OLAP-трафика, где каждый запрос уникален, пользы мало; для таких пулов лучше отключить подмену через prepared_statements_cache_size = 0.

Новая диагностика: SHOW INTERNER, SHOW INTERNER N, RESET INTERNER, колонка kind в SHOW PREPARED_STATEMENTS, новые поля в SHOW POOLS_MEMORY и Prometheus-метрики для количества записей, занимаемых байт, вытеснений, synthetic misses и длительности GC. По pg_doorman_servers_prepared_hits, pg_doorman_servers_prepared_misses и pg_doorman_clients_prepared_anonymous_evictions_total видно, кеш действительно помогает или только постоянно вытесняет записи.

См. Кеш Parse для анонимных prepared statements.

Полный changelog: https://ozontech.github.io/pg_doorman/changelog.html

Don't miss a new pg_doorman release

NewReleases is sending notifications on new releases.