Резервная копия, которую ни разу не восстанавливали, — не резервная копия
Непроверенные резервные копии баз данных предсказуемо выходят из строя: пустые дампы, отсутствующие роли, неверные флаги, потерянный ключ шифрования. Узнайте, как проверить восстановление и убедиться, что сохраняемый вами файл действительно работает.
Хуже всего обнаружить, что резервная копия не работает, именно в тот момент, когда она вам нужна. И всё же наиболее распространённый сценарий выглядит именно так: резервные копии один раз настроили, восемнадцать месяцев наблюдали зелёную галочку в панели управления, а затем восстановление создало пустую базу данных.
Тестирование восстановления резервной копии базы данных — это не просто рекомендация из списка необязательных best practices. Резервная копия — это утверждение, а пока вы не восстановили её хотя бы один раз, оно остаётся непроверенным.
Ниже разберём, как именно резервные копии выходят из строя и что должна проверять настоящая верификация.
Четыре способа, которыми резервная копия может незаметно оказаться бесполезной
1. Она пустая, и этого никто не заметил
pg_dump, завершившийся с ошибкой на середине выполнения, всё равно может создать файл. Дамп, выполненный для базы данных с неправильным именем, создаёт корректный валидный пустой файл. Для любой системы, которая проверяет только ненулевой код выхода или наличие файла, оба сценария выглядят как успешные.
Самая дешёвая проверка: посмотрите на размер и сравните его со вчерашним. Если сегодняшняя резервная копия весит 400 байт, а вчерашняя — 40 МБ, это говорит вам всё необходимое. А если она уже шесть месяцев весит 400 байт, то всё это время сообщала о проблеме.
2. В ней есть данные, но нет всего, что их окружает
pg_dump отдельной базы данных не включает роли и другие базы данных. Восстановите такой дамп на чистый сервер — таблицы появятся, но каждый GRANT будет ссылаться на несуществующую роль. Приложение подключится и получит отказ в доступе ко всему.
С расширениями ситуация такая же. Если схема зависит от pgcrypto или uuid-ossp, а на целевом сервере их нет, восстановление завершится ошибкой на середине, оставив после себя только часть таблиц.
3. Для нужного восстановления были выбраны неправильные флаги
В зависимости от формата pg_dump создаёт разные результаты, и обычно ошибка обнаруживается уже под давлением:
- Plain SQL восстанавливается с помощью
psqlи удобен для чтения человеком. Выборочное восстановление невозможно, а для больших баз данных этот формат работает медленно. - Custom format (
-Fc) восстанавливается с помощьюpg_restore, поддерживает parallelism и выборочное восстановление — именно его стоит выбирать для любых достаточно крупных баз данных.
Сделать резервную копию в plain format, потому что так было в руководстве, а затем во время инцидента обнаружить, что восстановить отдельную таблицу нельзя, — это вполне конкретный и предотвратимый вариант плохого дня.
4. Вы не можете расшифровать резервную копию
Если резервные копии зашифрованы — а они должны быть зашифрованы, — ключ является частью резервной копии. Ключ, который хранится только на потерянной машине или только в переменной окружения отключённого сервиса, — это ключ, которого у вас не будет в нужный момент.
Как выглядит настоящая проверка
Проверка — это не «существует ли файл». Нужно восстановить его в другом месте и задать ему вопрос.
# 1. Restore into a scratch database, not the live one
createdb verify_$(date +%Y%m%d)
pg_restore -d verify_$(date +%Y%m%d) --no-owner --no-privileges latest.dump
# 2. Ask it something only real data can answer
psql -d verify_$(date +%Y%m%d) -c "
select
(select count(*) from users) as users,
(select count(*) from orders) as orders,
(select max(created_at) from orders) as newest_order;
"
# 3. Drop it
dropdb verify_$(date +%Y%m%d)
Весь смысл — в шаге 2. То, что восстановление завершилось без ошибок, ещё ничего не говорит о наличии данных. Об этом говорят количество строк и проверка актуальности.
Вот три показателя, которые стоит проверять:
- Количество строк соответствует ожидаемому порядку величины. Не обязательно точному — данные меняются, — но если в таблице было 200 000 строк, а теперь осталось 12, это сбой.
- Самая новая запись действительно свежая. Если самый новый заказ в вашей «ежедневной» резервной копии датирован мартом, значит, задание резервного копирования остановилось в марте.
- Приложение действительно может подключиться. Направьте staging-инстанс на восстановленную базу данных и загрузите одну страницу.
Делайте это по расписанию, а не в свободную минуту
Реалистичная периодичность — раз в месяц, автоматически, с размещением результата там, где вы его заметите. Напоминание в календаре «проверить резервные копии» — это напоминание, которое вы просто отложите.
Чтобы процесс действительно работал, нужно сделать сбой заметным: если verification query возвращает меньше строк, чем задано порогом, это должно отправлять уведомление ответственному так же, как production-ошибка. Система резервного копирования, которая молча выходит из строя, ничем не отличается от отсутствия системы — вплоть до момента, когда она понадобится.
Как Dockup решает эту задачу
Три решения, каждое из которых направлено на конкретную описанную выше проблему.
Резервные копии хранятся в другом месте. Резервная копия на том же диске, что и база данных, — это не резервная копия, а копия, которая погибнет вместе с диском. Dockup напрямую отправляет резервные копии баз данных в object storage по мере их создания, поэтому файл никогда не зависит от хоста, на котором он был создан.
Они зашифрованы, а ключ не хранится на сервере. Резервные копии шифруются с помощью AES-256-GCM по мере передачи. Для восстановления важно то, что ключ хранится на платформе, а не в окружении резервируемого сервиса.
Результат без данных не считается резервной копией. Это напрямую решает проблему пустого файла: если dump завершается с ненулевым кодом или создаёт ноль байт, загрузка удаляется, а резервная копия помечается как неуспешная. У вас не появится список зелёных записей, среди которых одна указывает на файл размером 400 байт.
dockup db backup my-project/main-db --json # take one now
dockup db backups my-project/main-db --json # list them with sizes
Размеры в этом списке — самая простая проверка состояния, которая у вас есть. Следите за их динамикой.
Неприятный вопрос
Если ваша production-база данных будет уничтожена в ближайшие десять минут, сколько времени вам понадобится, чтобы восстановить её, и сколько данных вы потеряете?
Если вы не можете назвать оба числа, у вас нет стратегии резервного копирования — у вас есть только файлы резервных копий. Разница заключается исключительно в том, выполнял ли кто-нибудь когда-нибудь восстановление.
Часто задаваемые вопросы
Как часто нужно тестировать восстановление? Раз в месяц — разумный вариант по умолчанию; тестирование должно быть автоматизированным, а не ручным. Важно, чтобы сбой был заметным, а не чтобы периодичность была максимальной.
Почему восстановление завершилось успешно, но данных нет? Обычно дамп был создан для неправильной базы данных или завершился с ошибкой на середине, продолжая при этом записывать файл. Сравнивайте размеры резервных копий во времени: пустой дамп очевиден на графике размеров и незаметен в столбце статуса.
Нужно ли шифровать резервные копии? Да, а ключ должен храниться в месте, которое переживёт потерю машины. Зашифрованная резервная копия, ключ от которой находился на потерянном сервере, невосстановима.
Снимок — это то же самое, что резервная копия? Нет. Снимок тома сохраняет диск, включая состояние базы данных на конкретный момент. Логический дамп по своей природе согласован. Большинству команд нужны оба варианта, поскольку они защищают от разных сбоев.
