PostgreSQL 17: что нового и как мигрировать без даунтайма

Ключевые новинки PostgreSQL 17

Компания «ФинДата» — финтех-стартап, 3 кластера PostgreSQL 15 с суммарным объёмом 2.8 ТБ данных. Решили обновляться до PG 17 ради трёх киллер-фич:

ФичаЧто даётБыло в PG 15/16
Инкрементальный бэкапТолько изменённые блоки, экономия 90% трафикаТолько full backup
JSON_TABLESQL-стандартная функция для парсинга JSON в строкиjsonb_to_recordset (нестандартный)
VACUUM improvementsНа 2-3x быстрее на больших таблицахМедленный VACUUM на 100M+ строк
Logical replication slotsFailover slots при переключении репликиСлоты терялись при failover
MERGE improvementsRETURNING clause для MERGEMERGE без RETURNING
-- JSON_TABLE: парсинг JSON-массива в реляционные строки
SELECT jt.*
FROM orders,
  JSON_TABLE(
    order_data,
    '$.items[*]'
    COLUMNS (
      product_id INT PATH '$.id',
      name TEXT PATH '$.name',
      qty INT PATH '$.quantity',
      price NUMERIC PATH '$.price'
    )
  ) AS jt
WHERE orders.id = 12345;

-- Раньше приходилось писать:
SELECT (item->>'id')::int, item->>'name', (item->>'quantity')::int
FROM orders, jsonb_array_elements(order_data->'items') AS item
WHERE id = 12345;

Инкрементальный бэкап: экономия 90% места

До PG 17 pg_basebackup всегда делал полный бэкап. База 2.8 ТБ — это 2.8 ТБ каждый раз. Теперь:

# Полный бэкап (один раз в неделю)
pg_basebackup -D /backups/full_20260414 \
  --checkpoint=fast --wal-method=stream \
  --manifest-checksums=SHA256

# Инкрементальный бэкап (ежедневно) — только изменения
pg_basebackup -D /backups/incr_20260415 \
  --incremental=/backups/full_20260414/backup_manifest \
  --checkpoint=fast --wal-method=stream

# Размер сравнения
du -sh /backups/full_20260414   # 2.8T
du -sh /backups/incr_20260415   # 180G (6.4% от полного!)

Для восстановления нужно объединить полный + инкрементальные:

# Объединение бэкапов перед восстановлением
pg_combinebackup /backups/full_20260414 \
  /backups/incr_20260415 \
  /backups/incr_20260416 \
  -o /backups/combined_20260416

# Восстановление как обычно
pg_restore -D /var/lib/postgresql/17/main /backups/combined_20260416
Совет: Схема бэкапов для «ФинДата»: полный бэкап в воскресенье, инкрементальные ежедневно. Хранение: 4 полных + 6 инкрементальных = ~3.9 ТБ вместо 28 ТБ (7 полных бэкапов в неделю).

Миграция PG 15 → PG 17 без даунтайма

Два метода миграции:

МетодДаунтаймСложностьДля кого
pg_upgrade --link2-10 минутПростойБД до 500 ГБ, допустим короткий даунтайм
Logical replication~0 (секунды)СреднийБД любого размера, zero-downtime

Метод 1: pg_upgrade (быстрый, с коротким даунтайм):

# Установить PG 17 рядом с PG 15
apt install postgresql-17

# Остановить PG 15
systemctl stop postgresql@15-main

# Проверка совместимости
/usr/lib/postgresql/17/bin/pg_upgrade \
  --old-datadir=/var/lib/postgresql/15/main \
  --new-datadir=/var/lib/postgresql/17/main \
  --old-bindir=/usr/lib/postgresql/15/bin \
  --new-bindir=/usr/lib/postgresql/17/bin \
  --link --check

# Миграция (--link: хардлинки вместо копирования)
/usr/lib/postgresql/17/bin/pg_upgrade \
  --old-datadir=/var/lib/postgresql/15/main \
  --new-datadir=/var/lib/postgresql/17/main \
  --old-bindir=/usr/lib/postgresql/15/bin \
  --new-bindir=/usr/lib/postgresql/17/bin \
  --link

# Запустить PG 17
systemctl start postgresql@17-main

# Обновить статистику
/usr/lib/postgresql/17/bin/vacuumdb --all --analyze-in-stages

Метод 2: Logical replication (zero-downtime):

-- На PG 15 (источник): создать публикацию
ALTER SYSTEM SET wal_level = 'logical';
SELECT pg_reload_conf();
CREATE PUBLICATION full_migration FOR ALL TABLES;

-- На PG 17 (приёмник): создать подписку
CREATE SUBSCRIPTION migration_sub
  CONNECTION 'host=pg15-host dbname=findata user=replicator'
  PUBLICATION full_migration;

-- Дождаться синхронизации (мониторинг)
SELECT * FROM pg_stat_subscription;
-- Когда received_lsn ≈ latest_end_lsn — данные синхронизированы

-- Переключение: остановить запись на PG 15, дождаться финальной синхронизации
-- Переключить приложение на PG 17
-- DROP SUBSCRIPTION migration_sub;

Оптимизация VACUUM в PG 17

VACUUM в PostgreSQL — процесс очистки «мёртвых» строк (после UPDATE/DELETE). В PG 17 он стал значительно быстрее:

  • Параллельный VACUUM для индексов — до 3x ускорение на таблицах с несколькими индексами
  • Оптимизированное сканирование heap — пропуск unchanged страниц
  • Лучшее управление памятью — maintenance_work_mem используется эффективнее
-- Настройки VACUUM для большой БД (PG 17)
ALTER SYSTEM SET maintenance_work_mem = '2GB';
ALTER SYSTEM SET autovacuum_vacuum_cost_limit = 2000;  -- default 200
ALTER SYSTEM SET autovacuum_max_workers = 6;            -- default 3
ALTER SYSTEM SET vacuum_buffer_usage_limit = '512MB';   -- новое в PG 17

-- Мониторинг VACUUM
SELECT schemaname, relname,
  n_dead_tup,
  last_vacuum,
  last_autovacuum,
  vacuum_count
FROM pg_stat_user_tables
WHERE n_dead_tup > 10000
ORDER BY n_dead_tup DESC;

Результаты «ФинДата» после миграции на PG 17:

МетрикаPG 15PG 17
VACUUM на таблице 200M строк45 минут18 минут
Полный бэкап (ежедневный)2.8 ТБ180 ГБ (incremental)
JSON-запросы (агрегация)1200 мс380 мс (JSON_TABLE)
Failover (logical slot)Потеря данныхSlot переезжает автоматически

Чеклист миграции на PostgreSQL 17

Проверенный чеклист от «ФинДата» для безопасной миграции:

  1. Проверить расширения: SELECT * FROM pg_extension; — все ли совместимы с PG 17
  2. Проверить deprecated-функции: в PG 17 удалены to_tsvector без языка, ряд legacy-настроек
  3. Тест на staging: клон production через pg_basebackup, миграция pg_upgrade, прогон тестов
  4. Бенчмарк: pgbench на staging до и после миграции
  5. Приложение: проверить драйвер БД (libpq, JDBC, psycopg) на совместимость
  6. Мониторинг: после миграции 24 часа наблюдать pg_stat_statements, логи, replication lag
# pgbench до миграции (baseline)
pgbench -i -s 100 findata_bench
pgbench -c 32 -j 8 -T 60 findata_bench
# tps = 4520 (PG 15)

# pgbench после миграции
pgbench -c 32 -j 8 -T 60 findata_bench
# tps = 5180 (PG 17) — +14.6%
Важно: После pg_upgrade обязательно запустите ANALYZE на всех таблицах. Без актуальной статистики планировщик запросов может выбирать неоптимальные планы, и производительность упадёт.

Часто задаваемые вопросы

Да, pg_upgrade поддерживает обновление с любой версии PG 9.2+ до PG 17. Не нужно обновляться последовательно через 14, 15, 16. Однако чем больше разрыв версий, тем больше deprecated-функций могут сломать приложение — тестируйте на staging.

Нет, инкрементальный бэкап доступен только через pg_basebackup. pg_dump делает логический дамп (SQL) и не поддерживает инкрементальность. Для логических бэкапов используйте pg_dump + сжатие, для физических — pg_basebackup с --incremental.

PostGIS 3.5+ полностью совместим с PG 17. TimescaleDB 2.17+ поддерживает PG 17. Проверяйте совместимость конкретной версии расширения перед миграцией: pgxn.org или документация расширения.

Если вам нужен инкрементальный бэкап или JSON_TABLE — да. Если текущая версия работает стабильно и нет критичных фич — можно подождать PG 18. Обновление не бесплатно: тестирование, даунтайм, риски. Обновляйтесь, когда есть конкретная причина.

На мастере: SELECT * FROM pg_stat_replication; — столбцы sent_lsn, write_lsn, flush_lsn, replay_lsn. Разница между sent и replay — это лаг. Для алертинга: настройте Prometheus postgres_exporter с метрикой pg_replication_lag_seconds, алерт при > 30 секунд.

Нужна помощь с внедрением?

Настроим, оптимизируем и возьмём на поддержку вашу инфраструктуру. 15+ лет опыта, 8 серверов Dell Xeon в дата-центре МТС.

📞 Связаться с нами

Комментарии 0

Оставить комментарий

8 + 3 =