Почему миграции баз данных требуют собственного чек-листа
Разработчик пушит изменение, которое удаляет колонку. Пайплайн деплоя проходит зелёным. Приложение успешно разворачивается. Но миграция БД уже выполнилась, и этой колонки больше нет. Теперь старая версия приложения, которая всё ещё ссылается на эту колонку, не может запуститься. Команда понимает, что просто откатить приложение нельзя — нужно восстанавливать и базу данных. А восстановление БД означает потерю всех данных, записанных после выполнения миграции.
Такой сценарий разыгрывается в командах, которые относятся к изменениям в БД так же, как к изменениям в коде приложения. Профиль риска принципиально разный. Когда ломается код приложения, вы можете переразвернуть предыдущую версию. Когда ломается миграция БД, вы не всегда можете отменить сделанное. Данные могут быть потеряны. Ограничения могут быть нарушены. Схема может измениться так, что простой откат станет невозможен без полного восстановления из бэкапа.
Вот почему для миграций баз данных нужен собственный шаблон. Не универсальный чек-лист деплоя. А нечто специфичное для природы изменений схемы, трансформаций данных и необратимых последствий изменения продакшн-данных.
Проблема подхода к миграциям как к деплою кода
Деплой кода относительно безопасен, потому что он обратим. Вы разворачиваете версию 2, в ней баг, вы снова разворачиваете версию 1. Приложение перезапускается со старым кодом, и пользователи продолжают работать.
Миграции БД работают не так. Как только миграция выполнилась:
- Удалённые колонки нельзя восстановить без restore
- Переименованные таблицы ломают запросы, которые всё ещё используют старое имя
- Трансформации данных, которые удаляют или изменяют значения, нельзя отменить повторным запуском миграции
- Создание или удаление индексов может менять производительность запросов на часы или дни
Риск не только технический. Он операционный. Неудачная миграция может полностью остановить приложение, заблокировать таблицы на длительное время и потребовать координации между разработчиками, администраторами БД и эксплуатацией для восстановления.
Пятишаговый шаблон миграции базы данных
Хороший шаблон миграции — это не жёсткий скрипт. Это последовательность проверок и действий, которые снижают вероятность сюрпризов. У каждого шага есть чёткая цель, и пропуск любого шага увеличивает риск.
Следующая блок-схема иллюстрирует пятишаговый шаблон и ключевые точки принятия решений:
Шаг 1: Бэкап прежде всего
Перед любой миграцией необходимо сделать бэкап базы данных. Это не галочка для соответствия требованиям. Это последняя страховка, когда всё остальное терпит неудачу.
Бэкап должен быть пригоден для восстановления до точного состояния, предшествовавшего миграции. Это означает:
Обратимый скрипт миграции объединяет прямое изменение с откатом, чётко указывая, как отменить изменения при необходимости:
-- Up: Добавление колонки со значением по умолчанию
ALTER TABLE users ADD COLUMN last_login_at TIMESTAMP DEFAULT NULL;
-- Down: Удаление колонки (безопасно только если ни один код от неё не зависит)
ALTER TABLE users DROP COLUMN last_login_at;
- Файл бэкапа должен быть проверен на валидность, а не просто создан
- Процедура восстановления должна быть задокументирована и отработана
- Для миграций с высоким риском лучше сделать ручной бэкап непосредственно перед миграцией, чем полагаться на автоматические ежедневные бэкапы
Некоторые команды хранят автоматические бэкапы каждую ночь. Это нормально для рутинных операций. Но для миграции, которая удаляет таблицу или изменяет миллионы строк, сделайте бэкап прямо перед началом миграции. Бэкап должен храниться в месте, на которое не повлияет сама миграция.
Шаг 2: Пробный прогон на реалистичном окружении
Пробный прогон означает выполнение миграции на непродакшн-окружении, которое максимально точно отражает продакшн. Цель — выявить проблемы до того, как они попадут в продакшн.
Ключевое слово — «реалистичный». Запуск миграции на базе с десятью строками ничего не скажет о том, как она поведёт себя на базе с десятью миллионами строк. Миграция, которая выполняется за две секунды на пустой базе, может занять двадцать минут на продакшн-данных. В течение этих двадцати минут таблицы могут быть заблокированы, запросы могут вставать в очередь, а приложение может стать недоступным.
Правильное окружение для пробного прогона должно иметь:
- Схему, идентичную продакшену
- Объём данных, близкий к продакшену, или, по крайней мере, репрезентативный для самых больших изменяемых таблиц
- Аналогичные аппаратные или ресурсные ограничения, особенно по CPU и I/O
Запустите миграцию. Заметьте, сколько времени занимает каждый оператор. Следите за конфликтами блокировок. Проверьте ошибки. Если пробный прогон выявил проблемы, исправьте их до того, как трогать продакшн.
Шаг 3: Выполнение миграции в продакшене
Это критический момент. Миграция должна выполняться в часы низкой нагрузки. Не потому, что сама миграция провалится, а потому, что влияние любой проблемы меньше, когда затронуто меньше пользователей.
Во время выполнения активно мониторьте:
- Сколько времени занимает каждый оператор?
- Есть ли блокировки, которые мешают другим запросам?
- Продолжает ли приложение обрабатывать запросы, или соединения таймаутятся?
- Растёт ли частота ошибок в логах приложения?
Если миграция занимает больше времени, чем ожидалось, не предполагайте, что она в конце концов завершится. Имейте план прерывания или приостановки. Некоторые миграции можно разбить на более мелкие пакеты. Другие могут потребовать временного перевода приложения в режим обслуживания.
Шаг 4: Проверка результата
Не доверяйте зелёному коду выхода. Миграция может завершиться без ошибок и всё равно оставить базу данных в сломанном состоянии. Проверка означает, что схема соответствует ожиданиям, а приложение может подключиться и функционировать.
Проверьте:
- Что новые колонки существуют с правильными типами данных
- Что трансформации данных дали ожидаемые значения
- Выполните тестовый запрос, который использует изменённую схему
- Подключите приложение к базе данных и проверьте ошибки подключения
Если миграция добавила ограничения, проверьте, что существующие данные им удовлетворяют. Если миграция удалила ограничения, проверьте, что приложение всё ещё работает корректно без них.
Шаг 5: Мониторинг краткосрочных эффектов
Изменения схемы не перестают влиять на систему после завершения миграции. Они могут изменить планы выполнения запросов, использование индексов и привести к новым паттернам блокировок. Эти эффекты могут проявиться не сразу.
Мониторьте в течение следующих нескольких часов:
- Появились ли новые медленные запросы в базе данных?
- Стала ли частота ошибок в приложении выше, чем раньше?
- Возникли ли взаимоблокировки, которых не было ранее?
- Отвечает ли приложение в пределах нормальных задержек?
Используйте существующие инструменты мониторинга. Не полагайтесь на ручную проверку логов. Настройте оповещения о любой деградации, которая коррелирует со временем миграции.
Практический чек-лист для миграций баз данных
| Шаг | Действие | Проверка |
|---|---|---|
| Бэкап | Сделайте ручной бэкап перед миграцией | Проверьте, что файл бэкапа валиден и восстанавливаем |
| Пробный прогон | Запустите миграцию на стейджинге с данными, похожими на продакшн | Сравните время выполнения, проверьте ошибки, отметьте длительность блокировок |
| Выполнение | Запустите миграцию во время низкого трафика | Мониторьте длительность операторов, блокировки, ошибки приложения |
| Проверка | Проверьте схему и данные после миграции | Подтвердите колонки, ограничения и возможность подключения приложения |
| Мониторинг | Следите за изменениями производительности в течение 2-4 часов | Проверьте медленные запросы, частоту ошибок, взаимоблокировки |
Вывод
Миграции баз данных — это не деплой кода. Они несут необратимые последствия, требующие другого подхода. Пятишаговый шаблон — бэкап, пробный прогон, выполнение, проверка, мониторинг — даёт вашей команде структурированный способ снизить риск. Используйте его для каждой миграции, независимо от её размера. Миграция, которая кажется слишком простой, чтобы нуждаться в чек-листе, часто оказывается самой разрушительной.