Перейти к содержанию

D-08 · Миграция данных без остановки#

  • Версия: 2.1 · 2026-09-21 · по мастер-шаблону v6.0
  • Известно также как: переезд данных, live migration, перенос в другое хранилище, backfill, «как переехать и не уронить»
  • Этап: W3 · Данные: модель и хранилище — но применяется после того, как решение о переезде принято; окно сосуществования проверяется на W10
  • Стадия: под изменением — предмет и есть переход: на гринфилде переходить не от чего
  • Профиль: дорого изменить · высокое влияние → полная форма
  • Не решает: куда переезжать — это D-01; надо ли делить данные и по какой линии — D-07; как выкатывать код, который с этими данными работает, — D-09
  • Не путать с: D-07 — там решают, делить ли, здесь — как перебраться, когда решение уже принято
  • Карточки: DATA-17 миграции схемы без простоя · DATA-16 целостность и сверка данных · DATA-09 репликация · MSG-07 outbox и CDC · ARCH-13 strangler fig

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

Почему он первым. Данные говорят, что изменение системы ломает её чаще, чем её собственный код: в выборке инцидентов облачных сервисов конфигурация даёт 24,5 % причин, операционные ошибки 12,7 %, а ошибки в коде — 21,5 % (arXiv:2504.08865).

Область решения — один переезд одного набора данных. «Миграция в системе» — не решение.


1. Что выяснить#

Вопрос Где смотреть Заполняет
Что переезжает: объём, число сущностей, темп записи? Схема, метрики Длительность переноса, выбор формы
Все ли писатели этих данных известны? Права доступа, код, задания по расписанию, ручные правки Дисквалификатор
Чем будем сверять источник и приёмник — и сколько это стоит? Возможности обоих хранилищ Дисквалификатор и половина решения
Сколько можно быть недоступным — и можно ли вообще? Требования W0, продукт Отсекает или разрешает остановку на окно
Что произойдёт с данными, записанными во время переезда? Темп записи, способ догона Форма переезда
Кто читает эти данные и умеет ли читать из обоих мест? Потребители, включая отчётность и выгрузки Порядок переключения
Где точка невозврата и сколько времени до неё? Сам план переезда Обратимость на каждом шаге

Сверка — не этап миграции, а условие её обратимости#

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

Сверка бывает трёх сортов, и стоят они очень по-разному:

Сорт Что делает Когда достаточно
Счётная Сравнивает количества по срезам Первый фильтр; ловит потерю, не ловит порчу
Выборочная Сравнивает случайные записи целиком Постоянный режим во время переезда
Сплошная Сравнивает всё Перед точкой невозврата, хотя бы раз

Если сплошная невозможна по объёму — это факт, который меняет решение, а не деталь исполнения: он поднимает цену ошибки и обычно заставляет выбрать форму с переключением по частям.

Про второй вопрос#

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

2. Оси и дисквалификаторы#

Оси сравнения. Полнота сверки · обратимость на каждом шаге · окно недоступности · нагрузка на источник во время переезда · стоимость сосуществования · длительность.

Ось обратимости здесь главная, а не одна из. В остальных решениях обратимость — довод при прочих равных; здесь она определяет, что произойдёт в худший день. Форма, у которой откат есть только до первого шага, и форма, где откат есть на каждой когорте, различаются не удобством, а тем, чем кончится ошибка.

И у неё два значения, которые легко принять за одно.

Вид обратимости Что возвращает Чем обеспечивается
Операционная Возможность остановиться: не переносить дальше, вернуть трафик на источник Когорты, переключение чтения раньше записи, флаги
Информационная Состояние мира: сделанного как не бывало Тем, что приёмник наш и мы можем из него удалить

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

Практическое следствие одно и решающее: точка невозврата переезжает. Она оказывается не на переключении и не на договорной дате, а на первой переданной порции. На прогоне U-01 это выяснилось седьмым вопросом раздела 1 — ось его не задавала.

Заполняя ячейку обратимости, пишите оба значения или одно с оговоркой «приёмник наш». Ячейка «откат на каждой когорте» без этой оговорки читается как информационная обратимость и ею не является.

Дисквалификаторы.

  • Сверки нет. Нельзя убедиться, что перевезённое совпадает с исходным, — миграция необратима с первого шага. Отсекается не форма, а готовность начинать.
  • Писатели известны не все. Хотя бы один неучтённый — и приёмник расходится молча.
  • Переключение без подтверждения, что приёмник догнал. Сорок три секунды сетевого разделения дали сутки деградации именно потому, что «базы в обоих центрах содержали записи, отсутствующие в другом», и обратное переключение стало невозможным (GitHub, 2018). Подтверждение догона — не проверка перед переключением, а его предусловие.
  • Двойная запись без единого источника порядка. Тот же дисквалификатор, что в D-07: гонка и частичный отказ дают расхождение, невидимое до сверки. Во время миграции двойная запись часто неизбежна — тем более она обязана идти через журнал или захват изменений, а не через два вызова подряд.
  • Не назначены срок и владелец снятия старого пути. Временное состояние становится постоянным, когда его снятие никому не поручено. Здесь это дороже обычного: сосуществование двух хранилищ означает двойную стоимость и двойную правку на каждой задаче.

Первые два отсекают начало, третий и четвёртый — способ, пятый добавляет работу.

3. Матрица оценки#

Колонки — формы переезда из раздела 4, применимые к этому набору данных. В ячейках факты с пометкой источника.

Словарь пометок. [схема] · [замер] · [расчёт] · [требования] — из обязательств W0 · [проба] — результат пробного переноса на копии или на части данных · [нет данных].

Пометка [проба] — местная и важная. Единственное решение в наборе, где дешёвый эксперимент доступен почти всегда: перенести один процент и сверить. Оценка длительности и полноты сверки, полученная пробой, отличается от расчётной систематически, а не случайно.

Пример условный. Числа выдуманы, форма настоящая.

Ось Что записывать Остановка на окно Копия плюс догон По ключу, когортами
Полнота сверки Какой сорт возможен и сколько стоит Сплошная до включения [проба] Выборочная постоянно, сплошная перед переключением [расчёт] Сплошная на каждой когорте [расчёт]
Обратимость Что можно вернуть и на каком шаге Только до начала окна До переключения; после — только вперёд На каждой когорте
Окно недоступности Минуты 40 мин [проба] 0 0
Нагрузка на источник Прирост при переносе Нет — система стоит +30 % чтений на время переноса [замер] +5 % на когорту [расчёт]
Стоимость сосуществования Что платим, пока живут оба Нет Два хранилища, двойная запись Два хранилища дольше всех
Длительность От начала до снятия старого 40 мин 2 недели [расчёт] 2 месяца [расчёт]

Нулевой вариант — «не переезжать». Он законен и здесь чаще, чем кажется: стоимость переезда с сосуществованием, двойной записью и сверкой иногда превышает то, ради чего он затевался. Считать его надо явно.

Строка окна недоступности — единственная, где остановка выигрывает вчистую, и это стоит помнить: если окно есть, простой честный переезд дешевле любой изощрённой схемы и обратим целиком.

4. Типовые формы переезда#

Рынка здесь нет. Формы не устаревают, даты съёмки у раздела нет.

Форма Как устроена Когда верна Чем оборачивается при ошибке Статус у нас
Не переезжать Нулевой вариант Выигрыш меньше стоимости сосуществования Проблема, ради которой затевались, остаётся — но осознанно заполняется в проекте
Остановка на окно Останавливаем запись, переносим, включаем Окно есть и укладывается в обещание Окно оказалось длиннее расчёта, а назад уже нельзя — отсюда обязательная проба
Копия плюс догон Снимок, затем догон изменений из журнала, затем переключение Объём велик, остановка недопустима Догон не успевает за темпом записи: переключения не будет никогда
Двойная запись с фоновым переносом Пишем в оба, старое переносим фоном Нет журнала изменений, но есть контроль над всеми писателями Расхождение, невидимое без сверки; поэтому только через единый источник порядка
Чтение из обоих, запись в новое Читаем сначала из нового, при промахе из старого и дописываем Данные читаются неравномерно, «холодные» можно не переносить Холодный хвост не переезжает никогда, и старое хранилище не выключить
По ключу, когортами Арендаторы, диапазоны, регионы — по одной группе Ключ естественный и данные по нему не пересекаются Запрос, пересекающий когорты, ломается на время переезда
Strangler: новое — в новое Новые данные пишем в приёмник, старые остаются где были Исторические данные читаются редко и отдельно Два места навсегда; граница «новое/старое» становится вечной
Двойное чтение со сравнением Читаем из обоих и сравниваем, не переключаясь Не перенос, а проверка перед ним Принимают за миграцию; сам по себе он ничего не переносит

Формы комбинируются, и обычно правильно именно это. Типичная связка: двойное чтение со сравнением как проверка → копия плюс догон как перенос → по ключу как порядок переключения.

Источники раздела: Kleppmann — логи и почему двойная запись плоха · GitHub — разбор инцидента 21 октября 2018 · каталог практик — strangler и anti-corruption layer · реестр исследования

5. Эвристики#

Сверку проектируют раньше способа переноса. Не «перевезём и проверим», а «вот чем проверим — теперь выбираем, как везти». Форма, под которую нет сверки, отпадает независимо от своих достоинств.

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

Двойная запись — режим, а не приём. У неё обязаны быть единый источник порядка, сверка и срок. Без срока это не миграция, а новая постоянная архитектура, выбранная случайно.

Точка невозврата называется до начала. Один вопрос: после какого шага вернуться дороже, чем закончить? Ответ пишется в ADR. Команда, которая не знает ответа, узнаёт его в неподходящий момент.

Когорты дают откат, которого не даёт ничто другое — пока приёмник наш. Даже когда естественного ключа нет, его иногда стоит выдумать: диапазон идентификаторов не хуже арендатора. При чужом приёмнике когорты дают только право остановиться, и это стоит написать в ADR словами, а не подразумевать: команда, прочитавшая «откат на каждой когорте», будет считать, что вернуть можно всё.

Проба на одном проценте заменяет любую оценку длительности. Это единственное решение в наборе, где эксперимент дешевле рассуждения; пометка [проба] для того и заведена.

«Нет данных» здесь почти не бывает. Объём, темп записи, число писателей и стоимость сверки считаются по схеме, правам и метрикам за часы. Пустая ячейка обычно означает не «не померили», а «не нашли всех писателей» — то есть несработавший дисквалификатор.

6. Запись в ADR#

Поле ADR Чем заполняется
Контекст Что переезжает, откуда, куда, зачем; полный список писателей; объём и темп записи
Дисквалификаторы Какие формы отсечены; отдельно — что превратилось в работу до начала
Рассмотренные варианты Матрица раздела 3 снимком, включая нулевой вариант и результаты пробы
Решение Форма, порядок шагов, точка невозврата, порядок переключения чтения и записи
Обоснование Почему эта форма при этой сверке; что показала проба
Последствия Сверка как постоянный механизм; стоимость сосуществования; что делать, если догон не успевает
Условия пересмотра Раздел 7
Метод D-08 v<версия> · шаблон ADR v<версия> — рыночного снимка нет

Три строки обязательны, и без них запись считается неполной: способ сверки · точка невозврата · срок сосуществования и имя того, кто снимает старый путь.

Четвёртая обязательна, когда приёмник не наш: чем обратимость является на каждом шаге — операционной, информационной или обеими.

Связанное решение. Переезд данных почти всегда идёт вместе с выкатом кода, который с этими данными работает: у них общее окно и общая дата, а точка невозврата и откат общие только пока приёмник наш: при чужом приёмнике точка переезжает на первую переданную порцию (раздел 2), а у кода остаётся на переключении. Записываются они одним ADR — общий контекст, отдельные короткие записи, общие последствия (мастер-шаблон, раздел о связанных решениях).

7. Условия пересмотра#

  • Догон перестал успевать за темпом записи — переключения не будет, форму надо менять на ходу.
  • Сверка показала расхождение, которого не объясняет ни один известный писатель: список писателей неполон.
  • Точка невозврата пройдена, а условия изменились — это уже не пересмотр решения, а новое решение о том, что делать дальше.
  • Срок сосуществования истёк, старый путь не снят.
  • Объём или темп записи выросли настолько, что проба перестала быть представительной.
  • Появился потребитель, читающий данные напрямую, — его не было в списке.

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

Источники: Kleppmann — Using logs to build a solid data infrastructure · GitHub — October 21 post-incident analysis · Yan, Chen, Ma и др. — An Empirical Study of Production Incidents, arXiv:2504.08865 · microservices.io — pattern language · 00-workflow.md, шаг W3

История версий#

Версия Дата Изменение
2.1 2026-09-21 MINOR, по итогам вычитки Ш1. Раздел 6 больше не называет точку невозврата и откат безусловно общими с D-09 — ровно то, что раздел 2 говорит с версии 2.0, и то, что документ до сих пор опровергал сам себе внутри одного файла. Старым ADR: единственный — ADR-0002 прогона U-01, и его строка «общее у двух решений: окно, дата и точка невозврата» опровергнута находкой 2 того же прогона; приёмник там чужой. Принятый ADR не правится — читать его надо вместе с находками
2.0 2026-09-18 MAJOR, по итогам узкого прогона U-01 — первого применения этого документа. Ось обратимости разделена на операционную и информационную: пока приёмник наш, они совпадают; при чужом приёмнике расходятся полностью, и точка невозврата переезжает на первую переданную порцию. Поправлена эвристика о когортах, добавлена четвёртая обязательная строка записи. Старым ADR: он один — ADR-0002 того же прогона, написанный по v1.0. Переделывать его не нужно: различение операционной и информационной обратимости он уже проводит — в разделе «Замечание: ось обратимости не различает двух вещей», где оно и было найдено. Перепроверить в нём одно: четвёртой строки записи — чем обратимость является на каждом шаге — в его «Решении» нет, она осталась в замечании. ADR по прежним версиям намеренно не переписываются. (Строка переписана 2026-09-21 по развилке Ж3: прежняя редакция говорила «перепроверять нечего, документ не применялся ни разу» — буквально верно и на вопрос не отвечает.)
1.0 2026-09-17 Первая версия и первый документ третьей стадии. Собран из записи P-CHG-01 реестра исследования, поднятой на первое место данными о причинах инцидентов. 7 вопросов, 6 осей с обратимостью в качестве главной, 5 дисквалификаторов, 8 типовых форм переезда вместо рыночного слоя, местная пометка [проба], шестой пункт проверки — проведённая проба