Логическая репликация как способ переехать базой без простоя
Классический переезд базы данных — это pg_dump вечером, ожидание, пока досыплется импорт, и надежда, что за это время никто не оформит заказ. Логическая репликация убирает это ожидание: вы поднимаете новый сервер, база на нём синхронизируется, пока старая работает как обычно, и в момент переключения простой сокращается до секунд — того времени, что нужно приложению, чтобы переоткрыть соединение на новый адрес. Дальше — как это устроено и что обычно идёт не по плану.
Содержание
Чем логическая репликация отличается от физической
Физическая репликация копирует базу на уровне файлов и блоков диска — она побайтово воспроизводит внутреннее состояние СУБД на реплике. Это быстро и надёжно, но требует, чтобы источник и приёмник были практически идентичны: одна и та же СУБД, одна и та же мажорная версия, обычно одна и та же архитектура процессора. Для переезда «один сервер — другой такой же сервер» это отличный инструмент, но для переезда «старая версия — новая версия» или «одна платформа — другая» он не подходит в принципе.
Логическая репликация работает иначе. Источник декодирует поток изменений (в PostgreSQL это чтение WAL через logical decoding, в MySQL — разбор бинарного лога в формате ROW) и передаёт приёмнику не байты файлов, а логические операции: «в таблицу orders вставлена строка», «в таблице users обновлена строка с id=42», «из таблицы sessions удалена строка». Приёмник применяет эти операции через обычный SQL-движок — INSERT, UPDATE, DELETE.
Отсюда два практических следствия:
- Версии и платформы могут отличаться. Можно реплицировать со старой версии СУБД на более новую (частый сценарий — апгрейд мажорной версии без остановки), а в некоторых связках — и между разными продуктами с общим протоколом репликации. Точный список поддерживаемых комбинаций версий и направлений — это зона, где стоит свериться с официальной документацией конкретной СУБД под вашу задачу, потому что правила совместимости меняются от релиза к релизу.
- Гранулярность гибче. Физическая репликация тянет всю базу целиком. Логическая позволяет реплицировать выбранные таблицы или схемы — удобно, если на новый сервер переезжает не весь кластер, а конкретная база из multi-tenant инсталляции.
Плата за гибкость — цена на стороне процессора: логическое декодирование и построчное применение изменений нагружают CPU заметнее, чем потоковое копирование WAL. На сервере с интенсивной записью это стоит учитывать при выборе конфигурации новой площадки, особенно если помимо переезда вы одновременно поднимаете производительность процессора и дисковой подсистемы под целевую нагрузку.
Три фазы переезда: снимок, поток, переключение
Любой переезд через логическую репликацию проходит одни и те же три фазы, независимо от конкретной СУБД.
Фаза 1 — начальная синхронизация. В момент создания подписки на приёмнике движок делает согласованный снимок текущего состояния реплицируемых таблиц и копирует его целиком. Это по сути обычный дамп/рестор — самая тяжёлая по времени и нагрузке на диск часть процесса, но она не блокирует запись в источник: пока снимок копируется, приложение продолжает работать со старой базой как ни в чём не бывало.
Фаза 2 — непрерывная репликация изменений. Как только начальный снимок применён, приёмник переключается в режим потребления потока изменений с той точки, на которой был сделан снимок. С этого момента каждая транзакция, зафиксированная на источнике, доезжает до приёмника — обычно с задержкой от долей секунды до нескольких секунд в зависимости от нагрузки и сети. Эта фаза может длиться сколько угодно: часы, дни, недели. Именно она даёт вам свободу — можно без спешки прогнать нагрузочные тесты на новом сервере, проверить конфигурацию, убедиться, что мониторинг настроен, и только потом планировать переключение.
Фаза 3 — переключение (cutover). Короткое окно, в которое: приложение останавливает запись в старую базу (или переводится в read-only), дожидается, пока реплика догонит источник до нулевого отставания, и переключает строку подключения на новый сервер. Это единственный момент, где простой действительно есть — но измеряется он секундами, а не часами, потому что вся тяжёлая работа уже сделана заранее.
Таблица ниже — ориентир по длительности фаз для базы среднего размера (десятки–первые сотни ГБ), реальные цифры сильно зависят от вашей нагрузки и канала между серверами:
| Фаза | Что происходит | Ориентировочная длительность | Простой сервиса |
|---|---|---|---|
| Начальная синхронизация | Копирование снимка данных | От минут до нескольких часов | Нет |
| Непрерывная репликация | Поток изменений применяется на лету | От часов до недель (по вашему графику) | Нет |
| Переключение | Дожать отставание, переключить приложение | От секунд до 1–2 минут | Минимальный |
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНастройка на стороне источника
На источнике логическая репликация обычно требует явного включения — это осознанный шаг, а не поведение по умолчанию, потому что декодирование изменений расходует дополнительные ресурсы и место (WAL хранится дольше, пока не будет считан подписчиком). После включения нужного режима на источнике создаётся объект-публикация, который описывает, что именно реплицировать — все таблицы, конкретный список таблиц или таблицы по схеме:
-- PostgreSQL: публикация на выбранные таблицы
CREATE PUBLICATION migration_pub FOR TABLE orders, users, sessions;
-- альтернатива — вся база целиком
CREATE PUBLICATION migration_pub FOR ALL TABLES;
Дальше стоит сразу продумать три вещи, которые часто забывают на этом шаге:
- Права репликационного пользователя. Отдельная учётная запись только с правами на чтение изменений — не переиспользуйте суперпользовательский аккаунт приложения.
- Сетевой доступ. Новый сервер должен уметь достучаться до источника по нужному порту — если серверы в разных дата-центрах или разных провайдерах, заранее откройте правило файрвола именно на IP приёмника, а не «весь мир».
- Место под накопленные изменения. Пока подписчик не считал изменения (например, если синхронизация встала на паузу или сеть легла), источник обязан хранить эти данные у себя. Без мониторинга свободного места это способно неожиданно забить диск, поэтому место под журнал изменений на источнике стоит держать под контролем на всё время переезда.
Настройка на стороне приёмника и контроль отставания
На новом сервере создаётся объект-подписка, который указывает на источник и публикацию, после чего движок сам запускает начальную синхронизацию и переходит в потоковый режим:
-- PostgreSQL: подписка на публикацию с источника
CREATE SUBSCRIPTION migration_sub
CONNECTION 'host=old-server.example.com port=5432 dbname=app user=repl_user password=...'
PUBLICATION migration_pub;
С этого момента у вас на руках работающая копия, за отставанием которой нужно следить до самого переключения. Отставание считается в двух измерениях, и оба важны:
- По объёму — сколько байт изменений ещё не применено (запрос к системным представлениям репликации на источнике покажет, сколько «непрочитанного» накопилось для конкретного слота).
- По времени — какой временной лаг между моментом фиксации транзакции на источнике и моментом её применения на приёмнике.
Отставание в 0 байт и 0 секунд — это то состояние, которого вы добиваетесь перед переключением. Если база под нагрузкой пишет быстрее, чем приёмник успевает применять изменения, отставание будет расти постоянно, и «догнать» его в момент cutover не получится — надо разбираться с производительностью приёмника заранее, а не в ночь переезда. Общие принципы диагностики отставания — в статье как работает репликация и отставание реплики.
Отдельно стоит настроить алерты именно на этот лаг — не полагайтесь на визуальную проверку раз в час. Простой дашборд с метрикой отставания в системе мониторинга закрывает это без лишних трудозатрат.
Финальное переключение: что подготовить заранее
Само окно cutover должно быть коротким и заранее отрепетированным — импровизировать в этот момент дорого. Порядок действий, который стоит прописать в виде чек-листа и один раз прогнать на тестовом контуре:
- Заморозить запись в источник. Перевести приложение в режим обслуживания или read-only, либо остановить сервис записи (в зависимости от архитектуры — иногда достаточно закрыть порт базы для приложения, оставив открытым для реплики).
- Дождаться нулевого отставания. Проверить метрики лага — и по объёму, и по времени — до момента, когда они действительно упадут до нуля, а не «около нуля».
- Сверить контрольные суммы или количество строк на ключевых таблицах источника и приёмника. Это недорогая проверка, которая ловит расхождения до того, как на них наткнётся пользователь.
- Переключить строку подключения приложения на новый сервер — через DNS, через конфиг подключения или через балансировщик, в зависимости от того, что у вас уже есть.
- Снять режим только для чтения и вернуть сервис в обычный режим — уже на новом сервере.
- Оставить старый сервер в режиме наблюдения ещё некоторое время (от суток до недели) как страховку на случай, если что-то не заметили сразу.
Если переключение идёт по DNS, заранее снизьте TTL записи за день-два до переезда — иначе часть клиентов ещё долго будет стучаться в старый адрес даже после смены записи. Эта грабля разобрана отдельно в статье про TTL и растянутый на два дня переезд. Подготовьте и обратный план — если после переключения обнаружится проблема, вернуть трафик на старый сервер должно быть так же просто и быстро, а не превращаться во второй незапланированный переезд.
Типичные сложности и что не реплицируется автоматически
Логическая репликация — не зеркальная копия базы, а поток DML-операций (вставка/изменение/удаление строк) над уже существующей структурой. Отсюда вытекает главный источник сюрпризов: не все типы объектов и не все операции реплицируются автоматически, и перед переездом это нужно проверить явно, а не понадеяться.
Что обычно требует ручного переноса или отдельного внимания:
- Структура объектов (DDL). Схема таблиц, индексы, представления, хранимые процедуры, триггеры сами по себе логической репликацией, как правило, не тиражируются — целевая схема должна существовать на приёмнике заранее (её переносят отдельно, до создания подписки).
- Последовательности и автоинкременты. Значения счётчиков (sequences в PostgreSQL, auto_increment в MySQL) синхронизируются не всегда и не сразу — после переключения стоит явно проверить и при необходимости выставить текущее значение на приёмнике, иначе первая же вставка после cutover может упасть на конфликте ключа.
- Крупнообъектные типы и специфичные типы данных. Отдельные типы данных или большие объекты могут поддерживаться репликацией с оговорками или не поддерживаться вовсе — это то, что обязательно нужно свериться со списком ограничений конкретной СУБД под вашу версию и набор используемых типов.
- Изменения структуры во время переезда. Если на источнике во время фазы репликации накатывается миграция (добавили колонку, изменили тип), это может либо не долететь до приёмника автоматически, либо потребовать пересоздания публикации/подписки на затронутые таблицы — планируйте окно переезда так, чтобы не пересекаться с плановыми релизами схемы.
- Разные СУБД по разные стороны. Если переезд идёт не просто на новый сервер, а на другую платформу (например, с одного диалекта SQL на другой), логическая репликация в чистом виде между принципиально разными продуктами обычно не работает «из коробки» — для таких случаев существуют отдельные инструменты миграции данных, и это уже другая задача, не совпадающая по рискам с переездом «та же СУБД, другой сервер», и требует отдельных инструментов миграции схемы и данных между диалектами.
Возьмите за правило: после настройки публикации и подписки явно свериться со списком того, что реплицируется, по документации именно вашей СУБД и именно вашей версии — там же обычно перечислены ограничения по типам объектов и известные нюансы конкретного релиза. Не полагайтесь на то, что «раз данные пошли — значит, реплицируется всё».
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Логическая репликация подходит для переезда между разными версиями СУБД?
Да, это одно из главных практических применений — переезд со старой версии на новую без остановки сервиса, потому что логический поток изменений не завязан на внутренний формат файлов конкретной версии так жёстко, как физическая репликация. Конкретные поддерживаемые направления и версии стоит сверять с документацией СУБД под вашу задачу.
Сколько будет длиться реальный простой при переключении?
При аккуратной подготовке — от нескольких секунд до одной-двух минут: это время на дожатие отставания до нуля и переключение строки подключения приложения. Если отставание перед переключением не нулевое, простой растянется на то время, что нужно приёмнику, чтобы догнать источник.
Что делать, если после переезда приложение упало с ошибкой дублирующегося ключа?
Первое, что стоит проверить — синхронизацию последовательностей/автоинкрементов: если счётчик на приёмнике отстаёт от максимального id в таблице, первая же вставка после переключения конфликтует с уже существующей строкой.
Нужно ли останавливать приложение на всё время начальной синхронизации?
Нет, это ключевое преимущество подхода — начальная синхронизация читает согласованный снимок данных, не блокируя запись в источник; приложение продолжает работать в обычном режиме, пока копируется снимок и параллельно догоняется поток изменений.
Можно ли реплицировать только часть базы, а не всё целиком?
Да, публикацию можно ограничить конкретными таблицами или схемами — удобно, если переезжает не вся база, а отдельный поднабор данных, например одна из баз multi-tenant инсталляции.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →