Миграции и совместимость
Взрослый блок темы: его спрашивают там, где система живёт под нагрузкой и обновляется без остановки. Проверяют одну вещь - понимаешь ли ты, что изменить структуру и привести в порядок уже накопленные данные это две разные задачи.
Стержень: миграция меняет схему И приводит в соответствие ей накопленное. Вторую половину забывают чаще всего, потому что после первой всё выглядит работающим.
// Формулировки: «как переименовать колонку без простоя?», «почему новую колонку делают необязательной?», «миграция на 50 миллионов строк»
Три шага для новой обязательной колонки
Обязательная колонка требует значения для каждой существующей строки - иначе база просто не даст её создать. А осмысленного значения для прошлых записей обычно нет: если раньше поле «канал привлечения» не заполняли, то и взять его для старых клиентов неоткуда.
Стандартный путь состоит из трёх шагов, и каждый едет отдельным релизом. Добавить колонку необязательной - работающий код её не замечает, ничего не ломается. Заполнить историю по согласованному правилу. И только потом сделать обязательной.
Самое интересное здесь - второй шаг, и он не технический. Правило заполнения истории это бизнес-решение: поставить всем значение по умолчанию, вычислить из соседних полей, оставить пустым и пометить на ручную обработку. У каждого варианта своя цена в отчётности, и выбирать должен тот, кто по этой отчётности принимает решения.
// Аналитик тут нужен ровно затем, чтобы этот выбор состоялся осознанно. Без него разработчик проставит «прочее» всем миллионам старых записей, и через год никто не сможет отличить настоящее «прочее» от заглушки.
Обратная совместимость и приём расширить-сжать
Совместимость определяется не по документации, а по работающему коду. При постепенном обновлении старые и новые экземпляры приложения какое-то время живут одновременно и ходят в одну и ту же базу. Значит, схема обязана устраивать обе версии сразу.
Отсюда следует простая классификация. Добавление необязательной колонки безопасно: старый код её не видит и не расстраивается. Удаление и переименование - нет: старый код обратится к тому, чего уже нет, и упадёт.
Переименование делают в четыре шага. Добавить новую колонку. Настроить запись в обе - старая версия пишет в свою, новая в обе. Перенести накопленное и переключить чтение на новую. И только когда старая версия нигде не работает - удалить прежнюю колонку.
// Медленнее, зато на каждом шаге система остаётся работоспособной для обеих версий кода, и в любой момент можно остановиться. Одношаговое переименование роняет ещё живые экземпляры старой версии - причём не все сразу, а по мере того, как на них попадают запросы, что делает картину особенно запутанной.
Тихие потери и большие объёмы
Смена типа с потерей точности не даёт никакой ошибки. Миграция проходит успешно, приложение работает, тесты зелёные, а копейки во всех суммах округлились. Всплывает это на сверке или в отчёте, иногда через месяцы, когда исходные значения уже неоткуда взять - они перезаписаны.
Миграция на десятках миллионов строк не должна идти одной транзакцией. Длинная блокировка кладёт систему, журнал транзакций распухает, а откат такой операции занимает столько же времени, сколько она сама. Обрабатывают пакетами по несколько тысяч строк, с паузами между ними, чтобы дать базе разгрестись.
// И всегда заранее продумывают план отката с честным указанием точки невозврата - момента, после которого вернуться уже нельзя. Удалённые данные не воскресают, потерянная точность не восстанавливается. Знать, где эта точка, надо до начала работ, а не в процессе.
Как отвечать: «Нужно переименовать колонку в большой рабочей таблице. Как без простоя?»
Приёмом расширить-сжать, в четыре шага. Сначала добавляю новую колонку и настраиваю запись в обе: старая версия кода продолжает работать со своей, новая пишет в обе сразу. Потом переношу накопленные значения пакетами по несколько тысяч строк, чтобы не держать длинную блокировку на большой таблице. Дальше переключаю чтение на новую колонку и убеждаюсь по метрикам и логам, что к старой больше никто не обращается - это отдельный шаг, а не предположение. И только после этого, обычно через релиз или два, удаляю прежнюю. Каждый шаг совместим с обеими версиями приложения, поэтому в любой момент можно остановиться и откатиться без потерь.
Кандидат даёт полную последовательность, объясняет назначение каждого шага и отдельно упоминает проверку перед удалением. Именно её обычно пропускают, а без неё последний шаг снова роняет прод.
На чём валятся
- −− Переименовывают колонку одним шагом и роняют работающие экземпляры старой версии.
- −− Меняют тип поля и молча теряют точность: ошибки нет, деньги округлились.
- −− Забывают привести в соответствие накопленные данные, изменив только структуру.
- −− Выполняют миграцию на миллионах строк одной транзакцией.
- −− Не описывают правило разбора при разделении поля и судьбу неразобранных значений.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.
- Нужно переименовать колонку в большой рабочей таблице. Как это делают без простоя?A)Переименовать сразу в момент релизаB)Добавить новую, дублировать запись, потом убрать старуюC)Остановить сервис на время операцииD)Создать представление с новым именем и оставить всё как есть
показать ответ и разбор
+B)Добавить новую, дублировать запись, потом убрать старую// разбор: Приём известен как расширить-сжать: сначала добавляют новую колонку и пишут в обе, потом переносят накопленное и переключают чтение, и только затем, когда старая версия кода нигде не работает, удаляют прежнюю колонку. Каждый шаг совместим с обеими версиями приложения.
- Что аналитик обязан описать для миграции, разделяющей одно поле на два?A)Ожидаемое время выполнения операцииB)Размер таблицы после измененияC)Имя разработчика, который её выполнитD)Правило разбора и судьбу остатка
показать ответ и разбор
+D)Правило разбора и судьбу остатка// разбор: Разделение поля «ФИО» на части упирается в реальность: двойные фамилии, отсутствующее отчество, мусор вроде «не указано». Нужно правило разбора и решение по остатку — оставить в резервном поле, пометить на ручную проверку или отклонить. Без этого миграция молча испортит часть данных.
- Миграция изменила тип поля и потеряла точность. Когда это обнаружат?A)Сразу при выполнении миграцииB)На сверке данных или в отчётностиC)При следующем резервном копированииD)При перезапуске приложения
показать ответ и разбор
+B)На сверке данных или в отчётности// разбор: Такие потери тихие: миграция проходит успешно, приложение работает, а копейки округлились. Всплывает это на сверке с бухгалтерией или в отчёте, где итог не сходится, — иногда через месяцы, когда восстановить исходные значения уже неоткуда. Поэтому перед изменением типа делают проверку на тестовой копии.
- Зачем к миграции готовят план отката?A)Этого требуют правила оформления релизовB)Чтобы ускорить выполнение самой миграцииC)Чтобы вернуться к рабочему состоянию при сбоеD)Чтобы уменьшить нагрузку на базу данных
показать ответ и разбор
+C)Чтобы вернуться к рабочему состоянию при сбое// разбор: Не всякая миграция обратима: удалённые данные не воскресают, а потерянная точность не восстанавливается. Поэтому план отката продумывают заранее и честно указывают, где точка невозврата. Для необратимых шагов страховкой служит резервная копия и проверенная процедура восстановления.
- Миграция на пятьдесят миллионов строк идёт часами и блокирует таблицу. Что предложить?A)Выполнить её в ночное окно целикомB)Разбить на пакеты и выполнять постепенноC)Увеличить таймаут блокировки в настройкахD)Отключить проверки целостности на время
показать ответ и разбор
+B)Разбить на пакеты и выполнять постепенно// разбор: Обработка порциями по несколько тысяч строк с паузами не держит длинную блокировку и не раздувает журнал транзакций. Процесс идёт дольше по календарю, зато система остаётся живой, а при сбое продолжается с последней обработанной порции. Ночное окно перестаёт спасать, как только объём перерастает его длительность.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.