ADG Оставить заявку
Блог Данные и аналитика 4 мин чтения

PostgreSQL 16 в продакшне: параллельные запросы, логическая репликация со standby и что показал pg_stat_io

После перевода нескольких DWH-кластеров на PG 16 собрали реальные наблюдения: parallel query, логическая репликация со standby и новый pg_stat_io в деле.

Контекст момента

PostgreSQL 16 в продакшне первые месяцы - параллельные запросы, логическая репликация с резервного, улучшения pg_stat

Когда PostgreSQL 16 вышел GA в сентябре, мы планировали осторожную миграцию одного кластера до конца года. В итоге мигрировали несколько - рабочая жизнь не спрашивает. Сейчас примерно три месяца продакшн-эксплуатации, и есть что рассказать без приукрашивания.

Параллельные запросы: ускорение на аналитике реальное

Главный практический результат, который стоит назвать сразу: аналитические отчёты на двух DWH-кластерах стали работать заметно быстрее. На одном клиенте - финансовая группа с историческими агрегатами за несколько лет - тяжёлые запросы с GROUP BY по нескольким измерениям сократили время с 40+ секунд до 25-28. На втором - промышленный холдинг, отчёты по выпуску продукции - картина похожая, отдельные запросы ускорились на треть.

Оба случая объединяет одно: запросы полностью сканируют большие таблицы без возможности использовать индекс. Именно здесь parallel query в PG 16 помогает - планировщик охотнее распараллеливает sequential scan и hash aggregation. Ключевые параметры, которые нам пришлось осознанно выставить:

  • max_parallel_workers_per_gather - по умолчанию 2, мы подняли до 4 на серверах с 16+ ядрами. Выше идти осторожно: параллелизм жрёт память и воркеры.
  • parallel_tuple_cost и parallel_setup_cost - снизили от дефолтных значений. Планировщик по умолчанию консервативен в выборе параллельного плана; чуть сдвинуть cost_model в сторону параллелизма оказалось полезным.
  • min_parallel_table_scan_size - опускали до 64MB на кластерах с небольшими, но активно сканируемыми таблицами.

Важная оговорка: OLTP-нагрузка от параллелизма не выиграла вообще. Point-lookups по индексу, INSERT-тяжёлые потоки, высококонкурентные транзакции - там изменений нет, и это нормально. Parallel query не серебряная пуля, а инструмент для конкретного профиля нагрузки.

Логическая репликация со standby: наконец-то

Это новшество PG 16, которого реально ждали. До этого логическая репликация могла работать только с primary: standby не умел быть источником для подписчика. Теперь умеет.

У нас это разблокировало конкретный пайплайн. Был клиент, где физический standby держался для HA, а отдельная задача - стримить изменения в аналитическое хранилище через логическую репликацию. Раньше репликация шла с primary, создавая на него дополнительную нагрузку WAL-декодирования. Теперь декодирование переехало на standby.

Нюансы, которые не сразу очевидны:

  • Standby должен иметь wal_level = logical - это требование к primary, потому что WAL-уровень устанавливается там. Сам standby наследует уровень.
  • recovery_min_apply_delay должен быть нулём или минимальным, иначе подписчик получает данные со смещением относительно primary, что может ломать предположения о latency в downstream-пайплайне.
  • При переключении primary-standby логическая репликация ломается - слот остаётся на старом standby, который теперь primary. Это не баг, это архитектурное ограничение: автоматического переноса слота нет. Мы обрабатываем это скриптом в рамках процедуры failover.

На практике подход работает - нагрузка на primary снизилась, пайплайн стабилен. Но failover-процедуру надо проговаривать заранее, а не в момент аварии.

pg_stat_io: I/O диагностика наконец стала взрослой

О pg_stat_io мы писали ещё когда готовились к миграции осенью - тогда тестировали на стенде. Теперь три месяца продакшн-наблюдений, и можно говорить предметно.

Главное, что изменилось: мы видим, кто именно читает с диска. pg_stat_io разбивает I/O по backend_type (client backends, autovacuum, WAL sender, checkpointer и т.д.) и по context (bulkread, bulkwrite, normal, vacuum). Это принципиально другой уровень по сравнению с тем, что давал pg_stat_bgwriter.

Конкретный случай: на одном кластере после миграции заметили повышенный reads у autovacuum. Оказалось, что autovacuum_vacuum_cost_delay был занижен слишком агрессивно - autovacuum читал активно, конкурируя с клиентскими запросами. Без pg_stat_io мы бы это ловили через iostat и корреляцию по времени. С ним - за 20 минут.

Что в pg_stat_io пока требует привычки: статистика накопительная с момента старта (или последнего pg_stat_reset()). Надо выстраивать мониторинг с дельтами, иначе абсолютные числа за недели мало что говорят. Мы добавили сбор дельт в наш мониторинг на базе Zabbix - с интервалом 5 минут достаточно для диагностики большинства ситуаций.

Итог на текущий момент

PG 16 в продакшне ведёт себя стабильно - ни одного инцидента, связанного с версией. Параллельные запросы дали ощутимый эффект там, где и должны были. Логическая репликация со standby закрыла реальную архитектурную потребность, хотя failover-сценарий требует ручного внимания. pg_stat_io быстро стал частью рутины диагностики.

Если кто-то ещё сидит на PG 14 и смотрит на 16 с осторожностью - по нашим наблюдениям, на DWH-нагрузке миграция оправдана. Параллелизм и pg_stat_io вместе - это уже не просто «новые фичи», а другое качество работы с аналитическими кластерами.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.