Резервное копирование — это страховочная сеть, а не стратегия отката миграций
Ваша команда только что выполнила миграцию базы данных, которая удалила таблицу orders_archive. Данные были перенесены в новую таблицу, всё выглядело чисто. Но старая система, о которой все забыли, всё ещё читала данные из этой таблицы. Теперь таблицы нет, данных нет, и новая миграция для её воссоздания не из чего восстанавливать.
Или, возможно, вы изменили столбец price с INTEGER на DECIMAL, и пакетное задание, которое выполняется каждый час, всё ещё записывает целые числа в этот столбец, незаметно повреждая записи.
В такие моменты инстинкт понятен: «У нас есть резервные копии. Просто восстановим базу данных до состояния до миграции».
Это звучит разумно. Но последствия часто оказываются хуже исходной проблемы.
Для чего на самом деле нужны резервные копии
Резервные копии существуют для катастрофических сценариев. Пожар в серверной. Отказ массива хранения. Повреждённый диск. Случайное удаление критической таблицы администратором. В таких ситуациях восстановление из резервной копии — правильное решение. У вас нет другого выбора, и цена невосстановления — полная потеря данных.
Но неудачная миграция — это не катастрофа. Это рядовое операционное событие. И отношение к нему как к катастрофе создаёт новые проблемы.
Две проблемы отката через резервную копию
Потеря данных
Резервная копия — это снимок данных на конкретный момент времени. Если вы сделали бэкап в 2:00 ночи, а миграция упала в 10:00 утра, у вас есть восемь часов активности пользователей, которая существует только в вашей рабочей базе данных. Размещённые заказы. Обновлённые профили. Созданные тикеты поддержки. Изменения конфигурации.
Когда вы восстанавливаете бэкап от 2:00 ночи, все эти данные исчезают. Вернуть их невозможно, если у вас нет другого источника. Этот разрыв становится тем больше, чем больше времени прошло между созданием бэкапа и восстановлением. Даже если вы используете восстановление на момент времени (point-in-time recovery) и восстанавливаетесь на 9:59, вы всё равно теряете всё, что произошло в последнюю минуту.
Даунтайм
Восстановление базы данных — это не мгновенный процесс. Для баз данных размером в сотни гигабайт восстановление может занять часы. В течение этого времени ваше приложение не может нормально обслуживать трафик. Данные несогласованны, частично загружены или заблокированы процессом восстановления.
Сравните это с подходом roll-forward, когда вы запускаете новую миграцию, которая занимает минуты. Или с компенсирующим скриптом, который корректирует данные без остановки приложения. Откат через резервную копию вынуждает команду выбирать между потерей данных и длительным простоем, а часто и тем и другим.
Point-in-Time Recovery уменьшает проблему, но не решает её
Некоторые команды используют восстановление на момент времени (PITR), чтобы сократить разрыв в данных. Вместо восстановления до последнего полного бэкапа они восстанавливаются до определённой позиции в журнале транзакций, например, за минуту до запуска миграции.
Это помогает. Вы теряете меньше данных. Но вы всё равно что-то теряете. Транзакции, завершившиеся за секунды до миграции, исчезают. И само восстановление всё ещё занимает время. PITR лучше, чем полное восстановление из бэкапа, но это не чистый механизм отката.
Место резервного копирования в иерархии восстановления
У резервного копирования есть чёткая роль в восстановлении базы данных: это крайняя мера. Страховочная сеть на случай, когда всё остальное не сработало, и вы готовы принять потерю данных и даунтайм, потому что альтернатива хуже.
В зрелой команде резервные копии создаются регулярно и периодически тестируются. Но когда миграция идёт не так, команда не хватается за бэкап в первую очередь. Они проходят по иерархии:
Следующая блок-схема обобщает этот процесс принятия решений:
- Roll-forward: Написать новую миграцию, которая отменяет изменение или добавляет недостающий элемент.
- Компенсирующий скрипт: Запустить скрипт, который корректирует данные без полной миграции.
- Восстановление из бэкапа: Только после оценки компромиссов по потере данных и даунтайму.
Практический чек-лист перед использованием резервной копии
Прежде чем восстанавливаться из бэкапа, задайте эти вопросы:
- Можем ли мы написать миграцию, которая добавит обратно удалённую таблицу или столбец?
- Можем ли мы запустить компенсирующий скрипт, который восстановит потерянные данные из логов или других источников?
- Сколько данных мы потеряем, если восстановимся из последнего бэкапа?
- Сколько времени займёт восстановление, и может ли бизнес принять такой даунтайм?
- Есть ли способ оставить приложение частично работающим, пока мы исправляем данные?
Если ответ на первые два вопроса «да», вам не нужно восстановление из бэкапа. Если ответ на последние три вопроса «неприемлемо», вам нужно найти другой путь.
Вывод
Резервное копирование — это ваша страховочная сеть для катастроф, а не стратегия отката миграций. Когда миграция не удалась, начинайте с roll-forward или компенсирующих скриптов. Прибегайте к бэкапу только тогда, когда эти варианты исчерпаны и вы приняли цену потери данных и даунтайма. Команда, которая рассматривает бэкап как план отката по умолчанию, — это команда, которая будет терять рабочие данные и сон.