Как проверить, что бэкап рабочий, не восстанавливая всё
Бэкап отработал без ошибок, файл лежит в хранилище, размер вроде нормальный — и вы спокойны ровно до того дня, когда этот файл понадобится по-настоящему. А тогда вдруг выясняется, что архив битый, дамп не парсится или внутри вообще не то, что ожидалось. Полная репетиция восстановления всей системы решает эту проблему, но делать её каждый день никто не будет — слишком дорого по времени и ресурсам. Разберём, как дёшево и быстро убедиться, что конкретный бэкап рабочий, не разворачивая его целиком.
Содержание
- Зачем проверять бэкап, если он и так "есть"
- Уровень 1: файл вообще создался и весит разумно
- Уровень 2: проверка целостности архива без распаковки
- Уровень 3: выборочное восстановление одного-двух файлов
- Уровень 4: для баз данных — проверка, что дамп реально парсится
- Как часто запускать какой уровень проверки
Зачем проверять бэкап, если он и так "есть"
Самая частая иллюзия — бэкап существует, значит с ним всё в порядке. На практике бэкап может быть рабочим по всем внешним признакам и нерабочим по факту: скрипт отработал без ошибок, но записал пустой файл из-за упавшего до него шага; архив создался, но был повреждён при копировании в хранилище; дамп базы снят в момент блокировки и содержит частичную транзакцию. Мы разбирали похожий случай в статье бэкапы шли год и оказались нерабочими — там показано, как легко такое проходит незамеченным месяцами.
Проблема в том, что сам факт "скрипт завершился с кодом 0" почти ничего не гарантирует. Между "процесс не упал" и "данные внутри архива читаемы и корректны" — большая дистанция, и закрывать её нужно отдельными проверками, а не надеждой на удачу. Ниже — четыре уровня таких проверок, от почти бесплатных до заметно более затратных, и когда какой применять.
Уровень 1: файл вообще создался и весит разумно
Это самая простая и при этом критически важная проверка — её стоит встроить прямо в скрипт резервного копирования, а не выносить в отдельный процесс. Смысл: после создания бэкапа проверить, что файл существует, не имеет нулевой размер и не подозрительно мал по сравнению с обычным объёмом.
Минимальная версия на bash:
#!/bin/bash
BACKUP_FILE="/backups/db-$(date +%F).sql.gz"
MIN_SIZE_KB=1024 # порог для вашего случая, подбирается по факту
pg_dump mydb | gzip > "$BACKUP_FILE"
if [ ! -s "$BACKUP_FILE" ]; then
echo "ОШИБКА: файл бэкапа пуст или не создан" >&2
exit 1
fi
SIZE_KB=$(du -k "$BACKUP_FILE" | cut -f1)
if [ "$SIZE_KB" -lt "$MIN_SIZE_KB" ]; then
echo "ОШИБКА: бэкап подозрительно мал: ${SIZE_KB}KB (порог ${MIN_SIZE_KB}KB)" >&2
exit 1
fi
echo "OK: бэкап создан, размер ${SIZE_KB}KB"
Порог размера не берётся с потолка — посмотрите на размер бэкапов за последний месяц (du -sh /backups/*.sql.gz) и возьмите, например, 50-70% от типичного минимума. Резкое падение размера (была база 2 ГБ, стал дамп 200 КБ) почти всегда сигнал проблемы: не тот момент снятия, оборванное соединение, пустая база вместо нужной.
Отдельно проверяйте код возврата самой команды бэкапа, а не только итогового файла — в конвейере вида pg_dump | gzip > file код возврата $? относится к gzip, а не к pg_dump, и упавший дамп может дать код 0. Используйте set -o pipefail в начале скрипта, чтобы конвейер завершался с ошибкой, если упала любая его часть:
set -euo pipefail
Это уровень, который должен быть у вообще любого автоматического бэкапа независимо от того, какие инструменты вы используете дальше — специализированный (Borgbackup, restic, urbackup) или самописный.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверУровень 2: проверка целостности архива без распаковки
Следующий шаг — убедиться, что сам архив физически цел: не оборван, не поврежден при передаче по сети, читается штатными средствами формата. Ключевая особенность этого уровня — он не требует извлечения файлов на диск, поэтому занимает секунды даже для больших архивов.
Для tar.gz:
tar -tzf backup.tar.gz > /dev/null && echo "архив цел" || echo "АРХИВ ПОВРЕЖДЁН"
Флаг -t (test/list) читает содержимое архива и проверяет структуру, не записывая файлы на диск — если gzip-поток оборван или tar-заголовки повреждены, команда завершится с ошибкой ещё до конца чтения.
Для чистого gzip и zstd:
gzip -t backup.sql.gz && echo "gzip-поток цел"
zstd -t backup.tar.zst && echo "zstd-поток цел"
Для zip-архивов:
unzip -t backup.zip
Специализированные инструменты бэкапа почти всегда несут встроенную команду верификации, которая идёт дальше простого чтения структуры и проверяет контрольные суммы блоков данных:
# Borgbackup — проверка репозитория и (опционально) данных
borg check /path/to/repo
borg check --verify-data /path/to/repo # медленнее, но честнее
# restic — аналогично, с выборочной проверкой части данных
restic check
restic check --read-data-subset=10% # компромисс скорость/полнота
# Proxmox Backup Server
proxmox-backup-client verify <backup-id>
Мы разбирали настройку и грабли этих инструментов отдельно — см. статьи про Borgbackup и сравнение restic и Borgbackup, если ещё выбираете между ними.
Важный нюанс: проверка целостности архива говорит "структура цела, контрольные суммы сходятся", но не говорит "содержимое внутри — то, что вам нужно, и оно логически корректно". Битые файлы это отловит, случайно забэкапленную не ту базу — нет. За это отвечает уровень 3.
Уровень 3: выборочное восстановление одного-двух файлов
Здесь вы реально распаковываете небольшую часть архива во временную директорию и смотрите на содержимое глазами (или простым скриптом). Это не полная репетиция — вы поднимаете не всю систему, а один конкретный файл или запись, — но именно этот шаг даёт настоящую уверенность, что данные внутри читаемы и адекватны, а не просто формально существуют.
Для tar-архива — извлечь конкретный путь без разворачивания всего остального:
mkdir -p /tmp/backup-check
tar -xzf backup.tar.gz -C /tmp/backup-check ./etc/nginx/nginx.conf
cat /tmp/backup-check/etc/nginx/nginx.conf | head -20
Для Borgbackup — список архивов и точечное извлечение:
borg list /path/to/repo
mkdir -p /tmp/backup-check && cd /tmp/backup-check
borg extract /path/to/repo::2026-08-30 home/user/important.txt
Для restic — аналогично, с фильтром include:
restic snapshots
restic restore latest --target /tmp/backup-check --include /etc/nginx
Практический критерий выбора файлов для такой проверки — не случайный, а осмысленный: один конфиг, который вы точно узнаете при взгляде, и один файл данных приличного размера (не 0 байт, не крошечный служебный файл), чтобы проверить, что реальный контент, а не только метаданные, восстанавливается корректно. Если это архив образа диска или виртуальной машины, точечное извлечение отдельного файла возможно через монтирование образа в режиме только для чтения:
mkdir -p /mnt/check
mount -o ro,loop,offset=1048576 disk.img /mnt/check
ls /mnt/check
umount /mnt/check
Смещение (offset) зависит от таблицы разделов образа — его можно узнать через fdisk -l disk.img или parted disk.img print, глядя на начало первого раздела в байтах.
Уровень 4: для баз данных — проверка, что дамп реально парсится
Дампы баз данных заслуживают отдельного уровня, потому что "архив цел" (уровень 2) ничего не говорит о валидности SQL или бинарного формата внутри — gzip-поток может быть безупречен, а сам дамп — оборван на середине из-за сетевого сбоя во время pg_dump.
Для PostgreSQL в custom-формате pg_restore --list читает оглавление дампа без применения данных — если дамп оборван или повреждён, команда сразу выдаст ошибку:
pg_restore --list backup.dump > /dev/null && echo "дамп читается корректно"
Для дампов в текстовом SQL-формате (обычный pg_dump без -Fc) полноценной проверки без применения нет, но можно как минимум проверить синтаксис через --dry-run в psql (начиная с версии, где он доступен) или через синтаксический разбор в одноразовом контейнере с пустой базой:
docker run --rm -e POSTGRES_PASSWORD=test -d --name pg-check postgres:16
sleep 5
gunzip -c backup.sql.gz | docker exec -i pg-check psql -U postgres -v ON_ERROR_STOP=1 > /tmp/restore.log 2>&1
docker stop pg-check
Это уже не совсем "уровень 3 без уровня 4" — по сути это применение дампа в одноразовую БД, но локально, за секунды, без развёртывания всей системы вокруг. Для MySQL/MariaDB похожий приём:
docker run --rm -e MYSQL_ROOT_PASSWORD=test -d --name mysql-check mariadb:11
sleep 15
gunzip -c backup.sql.gz | docker exec -i mysql-check mysql -uroot -ptest
docker stop mysql-check
Если дамп синтаксически некорректен или обрывается на середине, вы получите явную ошибку прямо в логе — а не молчаливо "успешный" бэкап, который откажется восстанавливаться в день, когда он реально нужен. Практику восстановления базы из бэкапа мы разбирали подробнее в статье восстановление базы данных из бэкапа на практике.
Как часто запускать какой уровень проверки
Единого правила "проверяйте всё и всегда" не существует — цена растёт от уровня к уровню, и разумная стратегия строит частоту обратно пропорционально стоимости проверки:
| Уровень | Что проверяет | Стоимость | Частота |
|---|---|---|---|
| 1. Размер и факт создания | Файл не пуст и не аномально мал | Секунды, встроено в скрипт | При каждом бэкапе |
| 2. Целостность архива | Архив читается, контрольные суммы сходятся | Секунды-минуты в зависимости от размера | При каждом бэкапе или ежедневно |
| 3. Выборочное восстановление | Содержимое внутри реально читаемо | Минуты | Регулярно, не обязательно ежедневно (например раз в неделю) |
| 4. Валидность дампа БД | Дамп парсится СУБД без синтаксических ошибок | Минуты | Вместе с уровнем 3 или отдельно по расписанию |
| Полная репетиция восстановления | Вся система поднимается и работает с этих бэкапов | Часы, отдельное окружение | Реже, но систематически по календарю — см. репетицию восстановления виртуалки из образа |
Уровни 1 и 2 достаточно дёшевы, чтобы встраивать их прямо в сам процесс бэкапа — тогда неудачная проверка сразу превращается в алерт, а не в тихую запись в лог, которую никто не читает. Уровень 3 стоит закрепить за отдельным cron-заданием на выделенном или тестовом сервере, чтобы не нагружать продакшн лишним чтением. Полную репетицию восстановления системы делают реже (раз в квартал-полгода для большинства сценариев, чаще для критичных систем) именно потому, что это часы работы и отдельная инфраструктура — но делать её совсем — единственный способ убедиться, что весь процесс "от нуля до рабочей системы" действительно работает целиком, а не по частям.
Отдельный практический момент — сама проверка должна за что-то отчитываться, иначе она рискует превратиться в ещё один процесс, за которым никто не следит. Удобный лёгкий способ — дергать сервис healthchecks-подобного типа по завершении каждой проверки, чтобы получать алерт именно при отсутствии сигнала "всё ок", а не только при явной ошибке. Мы разбирали такую схему для cron-задач в статье про мониторинг cron-задач через healthchecks.io — тот же принцип применим и к проверкам бэкапов.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Достаточно ли уровня 2 (целостность архива), чтобы не делать полную репетицию восстановления вообще?
Нет. Целостность архива говорит, что данные не повреждены физически, но не проверяет логику восстановления целиком: правильно ли настроены права, поднимаются ли сервисы в нужном порядке, срабатывают ли миграции. Полная репетиция закрывает именно этот пласт рисков.
Можно ли автоматизировать уровень 3 полностью, без участия человека?
Да, и это разумно для регулярной практики — скрипт извлекает заранее известный контрольный файл и сверяет его контрольную сумму (sha256sum) с эталоном, снятым в момент создания бэкапа. Человеческий глаз нужен реже — например, при первом запуске новой схемы бэкапа или после смены формата.
Что делать, если проверка целостности архива (уровень 2) регулярно падает на каком-то одном источнике?
Это почти всегда сигнал проблемы на стороне создания бэкапа, а не хранения — оборванное соединение, нехватка места на диске в момент записи, конкурентный доступ к файлу. Стоит проверить логи именно шага создания бэкапа, а не искать проблему в архиве постфактум.
Нужно ли проверять каждый отдельный бэкап или достаточно выборки?
Уровни 1-2 — дешёвые, имеет смысл проверять каждый. Уровни 3-4 обычно применяют к выборке (например, последний бэкап каждого источника раз в неделю) — проверять абсолютно каждый снятый дамп на этом уровне избыточно для большинства нагрузок.
Что если данные меняются редко и бэкапы почти идентичны день ото дня?
Частота проверки должна зависеть не от того, как часто меняются данные, а от того, как часто может сломаться сам процесс бэкапа (обновление ОС, смена версии СУБД, ротация ключей шифрования) — эти изменения не зависят от активности данных.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →