Тестирование восстановления из бэкапа: бэкап, который никто не восстанавливал
31 января 2017 инженер GitLab во время инцидента случайно удалил каталог с боевой базой — 300 ГБ данных исчезли на глазах. Дальше началось интересное: из пяти способов бэкапа и репликации, которые у них были, не сработал ни один — дампы оказывались размером в пару килобайт, репликация отставала, снапшоты были не там. Спасла компанию случайная копия, снятая руками за 6 часов до этого для другой задачи. Их публичный постмортем — лучший учебник по теме, чем любая статья.
Вывод, который стоит присвоить до того, как это случится у тебя: бэкап, из которого никто ни разу не восстанавливался, — это не бэкап, а надежда. И проверять эту надежду — работа QA.
Бэкап ≠ восстановление
«Бэкап прошёл успешно» означает ровно одно: процесс записи завершился без ошибки. Он не означает, что:
- в архиве есть данные (а не пустой файл после
mysqldump, у которого не хватило прав); - архив не побит и распакуется;
- из него можно поднять рабочую систему;
- данные внутри консистентны (снимок сделан в момент, когда половина транзакций была на полпути).
Единственное доказательство, что бэкап живой, — успешное восстановление из него. Всё остальное — зелёная галочка, которой хочется верить.
RTO и RPO — два числа, без которых бэкап бессмысленен
Прежде чем что-то тестировать, договоритесь о двух цифрах:
- RPO (Recovery Point Objective) — сколько данных допустимо потерять, измеряется во времени. Бэкап раз в сутки = RPO 24 часа: при аварии теряешь до суток. Приемлемо для блога, катастрофа для платежей.
- RTO (Recovery Time Objective) — за сколько система должна снова работать. Если восстановление 500 ГБ занимает 9 часов, а бизнес заложил RTO 1 час — у вас несоответствие, и узнать о нём во время аварии — худший вариант.
QA проверяет не «есть ли бэкап», а укладывается ли реальное восстановление в обещанные RTO/RPO. Это измеримо — берёшь и меряешь.
Что реально ломается при восстановлении
Сбои почти никогда не в самой команде restore. Они в стыках:
- Пустой или битый архив. Дамп прошёл, но с ошибкой прав/места — внутри мусор. Ловится только распаковкой и проверкой контрольной суммы.
- Не тот момент времени. Нужно восстановиться на «за 5 минут до аварии», а есть только вчерашний полный дамп — point-in-time recovery не настроен.
- Разъехавшаяся схема. Бэкап старой версии БД, а код уже ушёл на новую схему — restore есть, а приложение на нём не стартует.
- Зависимости и секреты. Восстановили БД, но потеряли ключи шифрования / переменные окружения / внешние конфиги — данные есть, доступа нет.
- Чужое окружение. Бэкап снят на одной версии Postgres/железе, разворачивается на другой — несовместимость всплывает в самый неподходящий момент.
- Порядок и объём. Что восстанавливать первым, чтобы сервис поднялся; и хватит ли места/времени на полный объём под нагрузкой.
Restore drill: репетиция, а не надежда
Restore drill — это плановое учение: берём реальный бэкап и полностью разворачиваем его в изолированном окружении, как будто прод только что умер. Что проверяем:
- Восстановление проходит до конца, без ручных «а, тут ещё вот это допишем».
- Данные консистентны: счётчики, суммы, связи между таблицами сходятся с эталоном (не просто «файлы на месте»).
- Приложение на восстановленной базе реально запускается и работает — логин, ключевой сценарий, оплата.
- Замеряем время: уложились в RTO или нет.
- Проверяем последний бэкап и восстановление на разные моменты (вчера, неделю назад) — ротация и старые копии тоже должны быть живыми.
Делать это надо регулярно и по возможности автоматически — раз в квартал вручную забывается, а автоматический drill в CI ловит «сломалось молча» сразу.
Мониторить надо восстановление, а не «бэкап прошёл»
Классическая ловушка: алерт настроен на «джоб бэкапа упал». Джоб не падал — он честно записал 2 КБ пустоты. Алерта нет, все спокойны, данных нет.
Что мониторить на самом деле:
- размер бэкапа и его отклонение от вчерашнего (резкое падение = тревога);
- возраст последнего успешного бэкапа (не устарел ли за пределы RPO);
- результат последнего restore drill — зелёный только если из бэкапа реально поднялась рабочая система, а не если джоб записи вернул 0.
Чек-лист
- Определены и согласованы с бизнесом RTO и RPO для каждой критичной системы.
- Есть restore drill: бэкап регулярно разворачивается в изолированном окружении до рабочего состояния.
- Проверяется консистентность данных после восстановления, а не только наличие файлов.
- На восстановленной базе запускается приложение и проходит ключевой сценарий.
- Замеряется время восстановления и сверяется с RTO.
- Проверяется point-in-time восстановление (не только «вчерашний полный»).
- Восстанавливаются и старые/ротационные копии, а не только последняя.
- Учтены секреты, ключи шифрования, конфиги — без них данные бесполезны.
- Мониторинг смотрит на размер/возраст/результат drill, а не на «джоб не упал».
- Есть runbook восстановления, по которому сможет пройти дежурный в 4 утра, а не только автор.
Коротко — что забрать с собой
- «Бэкап прошёл» доказывает только запись. Живость бэкапа доказывает единственная вещь — восстановление из него.
- Без RTO/RPO бэкап нельзя протестировать: непонятно, что значит «успех».
- Ломается не команда restore, а стыки: битый архив, не тот момент, схема, секреты, чужое окружение.
- Restore drill — регулярный и по возможности автоматический — единственный способ знать, а не надеяться.
- Мониторь размер/возраст/результат восстановления, а не зелёную галочку джоба.
Почитать: GitLab — постмортем инцидента 31 января 2017 · Google SRE Book — Data Integrity