Перенос базы на другой хостинг — момент, где легко либо потерять данные, либо словить долгий простой. Подход зависит от того, сколько простоя допустимо: для пет-проекта хватит дампа в тихий час, для боевого сервиса нужна репликация с переключением за секунды. Разберём оба способа и как переключиться, ничего не потеряв.
Способ 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 на старой — статус подключения. Переключаться можно, когда отставание близко к нулю, а не на глаз.
Переключение приложения
- Заранее снизить TTL DNS / подготовить смену строки подключения, чтобы переключение было быстрым.
- Кратко остановить запись в старую базу (или перевести приложение в режим обслуживания).
- Дождаться, пока подписка догонит последние изменения.
- Синхронизировать последовательности вручную — логическая репликация их не переносит:
Иначе новые вставки начнутся с устаревшего значения и поймают конфликт по первичному ключу.SELECT setval('orders_id_seq', (SELECT max(id) FROM orders)); - Переключить
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 разобран в отдельной статье.