MAATRIX / Блог / Логическая репликация как способ переехать базой без простоя

Логическая репликация как способ переехать базой без простоя

MAATRIX

Классический переезд базы данных — это 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 должно быть коротким и заранее отрепетированным — импровизировать в этот момент дорого. Порядок действий, который стоит прописать в виде чек-листа и один раз прогнать на тестовом контуре:

  1. Заморозить запись в источник. Перевести приложение в режим обслуживания или read-only, либо остановить сервис записи (в зависимости от архитектуры — иногда достаточно закрыть порт базы для приложения, оставив открытым для реплики).
  2. Дождаться нулевого отставания. Проверить метрики лага — и по объёму, и по времени — до момента, когда они действительно упадут до нуля, а не «около нуля».
  3. Сверить контрольные суммы или количество строк на ключевых таблицах источника и приёмника. Это недорогая проверка, которая ловит расхождения до того, как на них наткнётся пользователь.
  4. Переключить строку подключения приложения на новый сервер — через DNS, через конфиг подключения или через балансировщик, в зависимости от того, что у вас уже есть.
  5. Снять режим только для чтения и вернуть сервис в обычный режим — уже на новом сервере.
  6. Оставить старый сервер в режиме наблюдения ещё некоторое время (от суток до недели) как страховку на случай, если что-то не заметили сразу.

Если переключение идёт по 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 ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →