PostgreSQLМиграцияDevOps

Как перенести базу PostgreSQL на другой хостинг без простоя

5 мин чтения

Перенос базы на другой хостинг — момент, где легко либо потерять данные, либо словить долгий простой. Подход зависит от того, сколько простоя допустимо: для пет-проекта хватит дампа в тихий час, для боевого сервиса нужна репликация с переключением за секунды. Разберём оба способа и как переключиться, ничего не потеряв.

Способ 1: dump и restore (простой допустим)

Самый простой путь, когда есть окно обслуживания. На время переноса запись в старую базу останавливают (приложение в режим обслуживания), снимают дамп и восстанавливают на новом сервере.

# на старом сервере
pg_dump -Fc -h old-host -U appuser -d appdb -f appdb.dump

# восстановить на новом
pg_restore -h new-host -U appuser -d appdb -j 4 appdb.dump

Простой равен времени дампа плюс восстановления. Для базы в несколько гигабайт это минуты. Глобальные объекты (роли) переносят отдельно через pg_dumpall --globals-only. Подробнее про дампы — в статье про бэкапы PostgreSQL.

Важная деталь: pg_dump снимает консистентный снимок на момент запуска (через MVCC), поэтому даже на работающей базе дамп не «размазан» по времени. Но изменения, сделанные после старта дампа, в него не попадут — поэтому на время переноса запись и останавливают.

Восстановление под другой ролью

На managed-базе владелец и имена ролей обычно отличаются от исходных. Чтобы pg_restore не падал на несуществующих ролях и правах, его запускают с флагами, которые пропускают владельца и ACL:

pg_restore -h new-host -U appuser -d appdb --no-owner --no-acl -j 4 appdb.dump

Объекты при этом создаются от имени подключающегося пользователя.

Способ 2: логическая репликация (near-zero downtime)

Если простой почти недопустим, используют логическую репликацию (PostgreSQL 10 и новее). Новая база подписывается на старую, получает начальную копию данных и затем в реальном времени догоняет изменения. Переключение делают, когда реплика синхронна, — простой измеряется секундами.

На старом сервере (publisher):

CREATE PUBLICATION mypub FOR ALL TABLES;

На новом (subscriber):

CREATE SUBSCRIPTION mysub
  CONNECTION 'host=old-host dbname=appdb user=repl password=...'
  PUBLICATION mypub;

Подписка сама скопирует существующие данные и продолжит стримить новые. Важные ограничения логической репликации:

  • реплицируются только данные таблиц — не последовательности (sequences), схема (DDL) и крупные объекты;
  • таблицам нужен первичный ключ или явный REPLICA IDENTITY;
  • схему на новой базе нужно создать заранее (например, накатить миграции).

Проверка перед переключением

Перед тем как направить приложение на новую базу, стоит убедиться, что данные совпадают:

SELECT count(*) FROM orders;   -- сравнить на старой и новой базе

Проверить ключевые таблицы по числу строк и, выборочно, по свежим записям. Расхождение означает, что репликация ещё не догнала или что-то отвалилось.

Для логической репликации отставание видно в системных представлениях: pg_stat_subscription на новой базе показывает время последнего полученного изменения, pg_stat_replication на старой — статус подключения. Переключаться можно, когда отставание близко к нулю, а не на глаз.

Переключение приложения

  1. Заранее снизить TTL DNS / подготовить смену строки подключения, чтобы переключение было быстрым.
  2. Кратко остановить запись в старую базу (или перевести приложение в режим обслуживания).
  3. Дождаться, пока подписка догонит последние изменения.
  4. Синхронизировать последовательности вручную — логическая репликация их не переносит:
    SELECT setval('orders_id_seq', (SELECT max(id) FROM orders));
    
    Иначе новые вставки начнутся с устаревшего значения и поймают конфликт по первичному ключу.
  5. Переключить DATABASE_URL приложения на новую базу и снять режим обслуживания.

Частые грабли

  • Несовместимость версий. Восстанавливать дамп нужно в ту же или более новую мажорную версию PostgreSQL, не в старую.
  • Не перенесены роли и права. pg_dump одной базы не содержит пользователей — нужен pg_dumpall --globals-only.
  • Забытые последовательности. После логической репликации id начинается заново → дубликаты и ошибки уникальности.
  • Отсутствующие расширения. CREATE EXTENSION (например, pg_trgm, postgis) должны стоять на целевой базе до восстановления.
  • Разная локаль и кодировка. Несовпадение LC_COLLATE меняет порядок сортировки и поведение индексов.

Чеклист

  • Выбран способ по допустимому простою: dump/restore или логическая репликация.
  • Схема и расширения созданы на новой базе заранее.
  • Роли перенесены через pg_dumpall --globals-only.
  • Данные сверены по числу строк перед переключением.
  • Последовательности синхронизированы (setval) после логической репликации.
  • DATABASE_URL переключён, старая база погашена только после проверки.

Перенос на managed-базу убирает половину ручной работы: целевой Postgres, бэкапы и доступ уже готовы, остаётся восстановить данные и переключить строку подключения. На Hostim managed Postgres поднимается за минуты, идёт с ежедневными бэкапами, а сам переезд приложения с VPS разобран в отдельной статье.

Читать дальше