MAATRIX / Блог / Проверка восстановления бэкапа раз в месяц: сценарий на 30 минут

Проверка восстановления бэкапа раз в месяц: сценарий на 30 минут

MAATRIX

Бэкап настроен, cron запускает его каждую ночь, в логе зелёная строка completed successfully, и так проходит год, а то и три. Первый раз кто-то реально открывает архив только тогда, когда сервер уже не отвечает, база повреждена, а клиенты ждут ответа именно сейчас. Ниже — не абстрактный совет «проверяйте бэкапы», а конкретный сценарий на 30 минут раз в месяц: что восстанавливать, куда, как убедиться, что внутри действительно рабочие данные, и что записать себе на память, чтобы через полгода не начинать разбираться заново.

Почему «бэкап создаётся» и «бэкап восстанавливается» — разные вещи

Типичная история выглядит так: скрипт бэкапа настроили один раз, при внедрении его один раз протестировали — восстановление прошло успешно, все выдохнули. С этого момента система работает годами: cron исправно вызывает pg_dump, restic backup или borg create, exit code всегда 0, размер архива в разумных пределах, алерты молчат. Из этого молчания рождается уверенность, что всё в порядке. Мы разбирали этот механизм подробнее в статье миф «бэкап создался без ошибок — значит, он рабочий»: код возврата процесса резервного копирования отвечает только на вопрос «не упал ли сам процесс», и ничего не говорит о том, восстановится ли из архива работающая система.

Реальность обычно расходится с этой уверенностью в нескольких типичных местах:

  • Изменилась схема бэкапа, а обновить тест забыли. Полгода назад добавили новый docker-volume с загруженными файлами, но в скрипт бэкапа его не включили — база бэкапится, файлы пользователей нет. Об этом узнают в момент восстановления, а не раньше.
  • Ключ шифрования есть только в одной голове. Бэкап зашифрован, ключ хранится в переменной окружения на сервере или в заметке у одного человека — при аварии именно этого сервера ключа тоже может не оказаться.
  • Ротация тихо удалила единственную рабочую копию. Скрипт хранит последние N архивов, но если N-й архив уже битый несколько недель, а никто не смотрел, к моменту аварии рабочих версий может не остаться вовсе.
  • Дамп снят в неудачный момент. База данных бэкапится без --single-transaction или без остановки записи, дамп содержит частично зафиксированную транзакцию — файл создаётся, размер нормальный, но pg_restore падает на середине или база после восстановления логически противоречива.

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

Зачем отдельное тестовое окружение, а не восстановление поверх продакшена

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

  1. Риск для рабочей системы. Восстановление — это запись поверх существующих данных или как минимум остановка сервиса на время операции. Ошибка в команде восстановления (не тот путь, не та база) превращает тест в реальный инцидент.
  2. Если бэкап испорчен, вы можете потерять последнюю рабочую копию. Восстанавливая архив поверх продакшена, вы рискуете затереть корректные текущие данные заведомо сомнительными.
  3. Тест теряет смысл как репетиция. Настоящая авария почти всегда означает, что боевого сервера уже нет или он недоступен — значит, и тренироваться нужно на сценарии «разворачиваем с нуля на другой машине», а не «докатываем поверх того же диска».

Для месячной проверки достаточно одноразового окружения, которое можно поднять и снести за полчаса:

  • Отдельный VPS с почасовой оплатой — поднимаете под тест, восстанавливаете, проверяете, удаляете. Это ближе всего к реальному сценарию аварии, когда старого сервера физически нет.
  • Изолированный контейнер или отдельная VM на существующем тестовом хосте, если под рукой уже есть стенд для таких задач.
  • Локальная машина с Docker, если проверяется не весь сервер целиком, а конкретный сервис (база, один volume).

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

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Сценарий на 30 минут: пошагово

Ниже — раскладка по минутам для типичного случая: сервер с PostgreSQL или MySQL и несколькими docker-volume с файлами, бэкап которых снимается через restic или borg в отдельное хранилище (S3-совместимое или SFTP).

0–5 минут — подготовка. Выбираете, какой именно бэкап тестируете: обычно последний ночной. Поднимаете тестовое окружение — новый VPS или контейнер с тем же дистрибутивом, что и в проде (совпадение версии ОС и версии СУБД важно: восстановление дампа PostgreSQL 16 в кластер версии 13 может повести себя иначе, чем в проде).

5–20 минут — восстановление. Пример для restic:

# список снапшотов в удалённом хранилище
restic -r s3:s3.example.com/backups snapshots

# восстановление конкретного снапшота во временную папку
restic -r s3:s3.example.com/backups restore latest --target /restore-test

Пример для дампа PostgreSQL:

createdb test_restore
pg_restore --no-owner --dbname=test_restore /restore-test/dump.sql.gz

Пример для docker-volume, упакованного в tar:

docker volume create test_appdata
docker run --rm \
  -v test_appdata:/data \
  -v /restore-test:/backup \
  alpine tar xzf /backup/appdata.tar.gz -C /data

Для восстановления образа целого сервера (например, снятого через Proxmox Backup Server или vzdump) — разворачиваете образ в новую VM на тестовом хосте и загружаете её.

Засекайте время каждого шага секундомером или просто фиксируйте date до и после команды — эта цифра понадобится на шаге документирования.

20–27 минут — проверка целостности. Подробности в следующем разделе.

27–30 минут — фиксация результата. Кратко записываете итог, пока детали свежи в памяти — иначе через неделю вспомнить нюансы будет сложно.

Если данных много и укладываться в 30 минут не получается — это тоже полезный результат: значит, реальный RTO больше, чем вы думали, и об этом стоит знать заранее, а не в момент аварии. Отдельный разбор того, как замерить время восстановления терабайта данных на практике, — тема соседняя, здесь же важно, что даже частичный тест на выборке данных за 30 минут почти всегда лучше, чем ноль тестов за год.

Проверка целостности, а не просто факта, что процесс завершился

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

Для базы данных:

  • Сравните количество строк в ключевых таблицах с зафиксированным ранее значением: SELECT count(*) FROM orders;, SELECT count(*) FROM users;. Если в проде на момент бэкапа было 48 213 заказов, а в тестовой базе после восстановления — 40 000, где-то потеряны данные.
  • Откройте несколько конкретных записей по ID, про которые вы точно знаете, что они существуют (последний заказ, последняя регистрация), и сверьте содержимое.
  • Проверьте максимальную дату/время в данных (SELECT max(created_at) FROM orders;) — она должна быть близка к моменту снятия бэкапа, а не на день-два раньше: смещение может указывать на то, что бэкапится не тот источник или ротация подсунула более старую копию.

Для файлов:

  • Сравните количество файлов и суммарный размер с ожидаемым (find /restore-test -type f | wc -l, du -sh /restore-test).
  • Если при бэкапе формируется манифест контрольных сумм — сверьте sha256sum нескольких файлов, а не только их наличие. Пустой файл с правильным именем пройдёт проверку «файл существует», но не пройдёт проверку хеша.

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

Здесь же стоит вернуться к мысли из статьи про миф успешного завершения: restore completed, exit code 0 и «файл открылся архиватором» — это необходимые, но не достаточные условия. Достаточное условие — данные внутри читаемы, актуальны и в ожидаемом объёме, а приложение с ними реально работает.

Что документировать: результат и время

Смысл ведения журнала — не бюрократия, а память команды длиннее, чем память одного человека. Минимальная форма — таблица в markdown-файле или простой гугл-таблице, без отдельного инструмента:

ДатаЧто тестировалиСнапшот/дампВремя восстановленияПроверка целостностиПроблемыСледующий тест
2026-08-29БД + volume appdatarestic latest (2026-08-29 03:00)14 минcount(*) совпал, приложение открылосьнет2026-09-29
2026-07-30БДrestic latest (2026-07-30 03:00)9 минcount(*) заказов расходится на 3%найдена гонка в скрипте бэкапа, снятие без --single-transactionисправлено, перепроверено 2026-08-05

Важно фиксировать не только «всё ок», но и фактическое время — это единственный источник реального RTO вместо цифры, придуманной для регламента. Если время восстановления растёт от месяца к месяцу вместе с объёмом данных, это видно заранее, а не в момент, когда окно простоя, обещанное клиентам, оказывается вдвое меньше фактического.

Журнал также закрывает практический вопрос «когда мы последний раз проверяли восстановление» — без записи на это обычно отвечают «кажется, весной», что для аудита или разбора инцидента не годится.

Частые грабли

  • Тестируют не тот бэкап, который реально используется при аварии. Например, проверяют локальную копию на том же сервере, а в проде при реальном отказе используется удалённая копия в другом хранилище с другими правами доступа — и выясняется, что доступ к ней настроен неверно только в момент аварии.
  • Тестовое окружение слишком отличается от прода. Другая версия PostgreSQL, другая версия Docker, другой набор системных пакетов — восстановление формально проходит, но в проде та же операция ведёт себя иначе. Совпадение основных версий стоит держать хотя бы приблизительно.
  • Тест проводят один раз при внедрении и больше не повторяют. Схема данных, объём и сам инструмент бэкапа меняются, а тест — нет. Через год «однажды проверенный» бэкап тестировался уже на совсем другой системе.
  • Восстанавливают только базу, забывая про файлы, конфиги и секреты. Полноценный сервис редко состоит из одной базы данных — переменные окружения, TLS-сертификаты, загруженные пользователями файлы тоже должны попадать в область проверки хотя бы раз в несколько циклов.
  • Считают тест пройденным, если восстановление просто не упало с ошибкой. Возврат к разделу выше: без проверки количества строк, контрольных сумм и хотя бы одного смок-теста приложения тест ничего не доказывает.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Что делать, если восстановление не уложилось в 30 минут?

Зафиксировать фактическое время как есть — это и есть цель упражнения: узнать реальный RTO, а не подогнать тест под удобную цифру. Если данных много, можно тестировать полное восстановление раз в квартал, а раз в месяц — восстановление выборки (одна база из нескольких, один критичный volume) за укладывающееся в получас время.

Нужно ли проверять восстановление каждого сервиса ежемесячно?

Не обязательно всех сразу. Разумная практика — критичные сервисы (платежи, основная база, продакшен-приложение) проверять ежемесячно, менее критичные (внутренняя вики, dev-инструменты) — раз в квартал. Приоритет отдаётся тому, простой чего дороже всего.

Можно ли восстанавливать бэкап на том же сервере, где он хранится?

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

Тестовое окружение стоит денег каждый месяц — как сэкономить?

Использовать VPS с почасовой оплатой: поднять под тест, снести сразу после проверки. 30–60 минут аренды в месяц стоят на порядки меньше, чем простой сервиса из-за неработающего бэкапа, обнаруженного в момент реальной аварии.

Как автоматизировать этот процесс, чтобы не забывать?

Минимум — календарное напоминание с чек-листом. Более надёжный вариант — скрипт (например, Ansible-плейбук), который сам поднимает одноразовое окружение, разворачивает последний бэкап, прогоняет базовые SQL-проверки и шлёт отчёт; на успешное завершение можно повесить пинг на dead-man's-switch вроде healthchecks.io, чтобы отсутствие отчёта само по себе было алертом.

Чем этот тест отличается от полноценных «учений» по восстановлению?

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

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →