Параметры запуска PostgreSQL
PgDoorman может задавать параметры PostgreSQL при открытии серверного
соединения, не меняя postgresql.conf, ALTER ROLE или
ALTER DATABASE. Это полезно, например, в таких случаях:
- В горячем OLTP-пуле план переключается на generic после решения
эвристики
plan_cache_mode = autoи обратно уже не возвращается.ALTER ROLE SET plan_cache_mode = force_custom_planзатронет любую другую нагрузку под этой ролью, а изменить нужно только один пул. - Приложение не задаёт
statement_timeoutилиidle_in_transaction_session_timeout, а быстро доработать его нельзя. Администратору БД нужно сессионное значение по умолчанию, которое сохранится после клиентскогоRESET ALL. - Одно приложение должно стабильно показывать конкретный
application_name, независимо от значения, которое передаст драйвер, чтобыpg_stat_activityи аудит оставались читаемыми.
Для этого используется startup_parameters: набор GUC PostgreSQL,
который pg_doorman добавляет в StartupMessage новых серверных
соединений пула.
Конфигурация
Значения применяются в три слоя. Более узкий слой переопределяет ключ из предыдущего.
[general.startup_parameters]
statement_timeout = "5s"
[pools.checkout.startup_parameters]
plan_cache_mode = "force_custom_plan"
work_mem = "64MB"
После SIGHUP или RELOAD через консоль администратора каждое новое
серверное соединение пула checkout открывается со значениями
statement_timeout = 5s, plan_cache_mode = force_custom_plan и
work_mem = 64MB. В других пулах остаётся только
statement_timeout = 5s из general; остальные значения берутся из
настроек PostgreSQL по умолчанию. Уже открытые бэкенды не меняются:
новые значения вступают в силу по мере ротации соединений.
В сквозном режиме auth_query, когда server_user не задан, запрос
аутентификации может вернуть необязательную колонку startup_parameters
типа text, json или jsonb с JSON-объектом. Значения из этой
колонки переопределяют general и настройки пула только для
конкретного пользователя.
SELECT
rolpassword AS passwd,
CASE rolname
WHEN 'vip' THEN '{"work_mem":"256MB"}'::text
ELSE NULL::text
END AS startup_parameters
FROM pg_authid
WHERE rolname = $1;
pg_doorman выбирает декодер по типу колонки, поэтому приведение ::text
не требуется. Содержимое должно быть JSON-объектом, а значения —
строками. Для других типов PostgreSQL, в том числе доменов поверх
jsonb, pg_doorman пишет предупреждение и игнорирует пользовательские
параметры из этой строки.
Выделенный режим auth_query, когда server_user задан, игнорирует эту
колонку и один раз пишет предупреждение на пару (пул, пользователь).
В этом режиме один серверный пул обслуживает разных пользователей,
поэтому пользовательские значения применить нельзя.
Изменения в пользовательской строке startup_parameters применяются
только к новым серверным подключениям и только после того, как
pg_doorman перечитает строку. Кеш auth_query хранит положительные
записи в течение auth_query.cache_ttl (по умолчанию час); при
обновлении кеша pg_doorman замечает изменение overlay и сбрасывает
динамический пул, чтобы следующий логин пересоздал его с новыми
значениями. Пока запись кеша не истекла, новые подключения клиентов
получают прежний overlay. Чтобы выкатить изменения немедленно: уменьшить
cache_ttl и сделать reload конфигурации, перезапустить pg_doorman или
дождаться истечения TTL. Бэкенды, которые уже выданы клиентам,
продолжают работать со значениями, сохранёнными при создании пула.
Что pg_doorman делает со значениями
pg_doorman добавляет итоговый набор параметров в StartupMessage
каждого нового бэкенда. PostgreSQL сохраняет эти значения как
сессионные значения по умолчанию (pg_settings.reset_val и
pg_settings.source = 'client'). Поэтому клиентские RESET ALL и
DISCARD ALL возвращают операторские значения, а не исходные
значения PostgreSQL.
Значение видно со стороны клиента:
checkout=> SHOW plan_cache_mode;
plan_cache_mode
-------------------
force_custom_plan
checkout=> SET plan_cache_mode = 'auto'; RESET ALL; SHOW plan_cache_mode;
plan_cache_mode
-------------------
force_custom_plan
Валидация
При загрузке конфигурации pg_doorman проверяет:
- Имена ключей должны соответствовать маске GUC PostgreSQL:
^[A-Za-z_][A-Za-z0-9_.]*$. Составные имена вродеauto_explain.log_min_durationдопустимы; произвольная пунктуация нет. - Зарезервированные ключи (
user,database,replication,options,role,session_authorizationи всё, что начинается с_pq_.) отклоняются. pg_doorman управляет ими сам, либо PostgreSQL обрабатывает их вStartupMessageособым образом. - Значения не должны содержать нулевой байт.
- Каждый уровень (
generalилиpool) должен помещаться в лимит для операторских параметров:MAX_STARTUP_PACKET_LENGTH(10000 байт) минус 512 байт, зарезервированных под служебные ключи pg_doorman.
Перед запуском каждого бэкенда pg_doorman снова проверяет объединённый
набор параметров по тому же лимиту. Слои, которые помещаются по
отдельности, могут превысить лимит после объединения: general + pool
может быть слишком большим сам по себе, а строка auth_query может
переполнить уже допустимый базовый набор. Любое превышение теперь
возвращается клиенту как PostgreSQL-ошибка с SQLSTATE 53400; пустой
или урезанный StartupMessage не отправляется. В предупреждении
записываются размеры в байтах, а
pg_doorman_startup_parameters_dropped_total увеличивается на каждой
отклонённой попытке запуска бэкенда.
Что происходит, если PG отвергает параметр
Если PostgreSQL отвергает заданный оператором параметр при запуске
бэкенда, pg_doorman возвращает клиенту ErrorResponse PostgreSQL без
изменений. Клиент видит тот же SQLSTATE (22023, 42704, 42501,
55P02 или любой другой код, который PostgreSQL вернул при отклонении
StartupMessage) и то же сообщение, что увидел бы при прямом
подключении к PostgreSQL.
pg_doorman не пробует повторить подключение без отклонённого параметра
и не отключает этот ключ автоматически для пула. Следующее подключение
клиента отправит тот же StartupMessage и получит ту же ошибку, пока
оператор не исправит конфигурацию.
Наблюдаемость
Итоговые параметры по каждому пулу видны через административную SQL-консоль:
admin> SHOW STARTUP_PARAMETERS;
user | database | parameter | value | source | state
------+----------+-------------------+-------------------+---------+--------
shop | checkout | plan_cache_mode | force_custom_plan | pool | applied
shop | reports | statement_timeout | 10s | general | applied
Веб-интерфейс показывает эти же строки на странице пула в секции «Startup parameters (operator-injected)».
В Prometheus:
pg_doorman_backend_startup_parameter_errors_total{pool, sqlstate}считает попытки запуска бэкенда, которые PostgreSQL отклонил из-за параметра, заданного оператором. Имя параметра и пользователя пишутся в строку лога уровняwarn; в лейблы они не включены, чтобы динамическиеauth_query-пулы не раздували количество серий.pg_doorman_startup_parameters_dropped_total{pool, reason}считает случаи, когда pg_doorman отклонилstartup_parametersдо отправкиStartupMessage: превышение лимита, неподдерживаемый тип или неверный JSON изauth_query, недопустимые ключи или значения, а также пользовательские значения, проигнорированные в выделенном режиме.
Практичное условие для алерта: если
pg_doorman_backend_startup_parameter_errors_total растёт по одному и
тому же пулу несколько минут подряд, новые подключения к этому пулу
падают на одном и том же GUC. Конфигурацию нужно исправить до возврата
трафика.
Когда это не нужно
- Приложение само задаёт параметр на каждом подключении. Дублирование в
startup_parametersдобавляет ещё одну настройку без изменения поведения. - Тюнинг на одну транзакцию (
SET LOCAL).startup_parametersзадают сессионные значения по умолчанию; параметры уровня транзакции должно выставлять приложение. - Значения, которые зависят от текущего запроса. Параметры запуска действуют для всех транзакций бэкенда на протяжении его жизни; режима «на один statement» нет.
Справочник
- Общие настройки:
startup_parameters. - Настройки пула:
pools.<name>.startup_parameters. - auth_query: сквозной и выделенный
режимы, чтение колонки
startup_parameters. - Команды администратора:
SHOW STARTUP_PARAMETERS. - Метрики Prometheus: полный список.