← Бэкапы
14 мин · средне · Урок 7 из 9

Бэкап баз: логический, физический и PITR

Чем pg_dump отличается от копии файлов кластера, зачем нужен архив WAL и как восстановиться на минуту до ошибочного запроса.

Почему базу нельзя просто скопировать

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

Такая копия либо не поднимется вообще, либо поднимется и будет тихо врать. Поэтому у баз свои инструменты, и их два класса.

Логический бэкап

Логический бэкап это выгрузка содержимого: команды и данные, из которых базу можно собрать заново.

pg_dump -Fc mydb > mydb-2026-08-23.dump
pg_restore -d mydb_new mydb-2026-08-23.dump

Флаг -Fc даёт сжатый формат, из которого pg_restore умеет восстанавливать выборочно: только схему, только данные, отдельные таблицы.

Сильные стороны: копия переносима между версиями и даже между машинами разной архитектуры и позволяет достать отдельную таблицу. Формат -Fp вдобавок читается глазами, это обычный SQL; содержимое -Fc смотрят через pg_restore -l.

Слабые: снимается долго на больших базах, грузит сервер, восстанавливается ещё дольше, потому что база заново строит индексы. Терабайтная база разворачивается из дампа часами, и это прямо бьёт в ваш RTO. Частично лечится параллелизмом: pg_restore -j 8 (и pg_dump -j для формата -Fd) раскладывает работу по нескольким процессам.

Отдельно: pg_dump снимает согласованный снимок за счёт долгой транзакции, а она удерживает горизонт видимости. VACUUM при этом работает, но не может убрать версии строк, умершие уже после старта дампа. На нагруженной базе многочасовой дамп заметно раздувает таблицы.

Физический бэкап

Физический бэкап это копия файлов кластера, снятая правильным способом:

pg_basebackup -D /backup/base -Ft -z -P

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

Сильные стороны: снимается быстрее логического, восстанавливается тоже быстрее (файлы просто кладутся на место), даёт основу для восстановления на точку во времени.

Слабые: копия привязана к мажорной версии сервера и к платформе (разрядность, порядок байт), выборочно достать одну таблицу нельзя, а объём до сжатия равен объёму кластера.

WAL и восстановление на точку во времени

Postgres пишет все изменения сначала в журнал предзаписи (WAL), и только потом они попадают в файлы данных. Если сохранять эти журналы непрерывно, появляется возможность, ради которой всё и затевается.

archive_mode = on
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'

Две оговорки. archive_mode применяется только при старте сервера, так что включение требует рестарта, а wal_level должен быть не ниже replica (это значение по умолчанию). И сам пример с cp взят из documentation как иллюстрация: он не делает fsync, поэтому в проде берут pgBackRest, WAL-G или barman.

Схема работы: раз в сутки физический бэкап, между ними непрерывная архивация WAL. При аварии вы разворачиваете последний базовый бэкап и проигрываете поверх журналы до нужного момента.

# postgresql.conf восстанавливаемого кластера
restore_command = 'cp /archive/%f %p'
recovery_target_time = '2026-08-23 14:29:00'
recovery_target_action = 'promote'

Оба параметра идут в postgresql.conf, а в каталоге данных создаётся пустой файл recovery.signal. Отдельного recovery.conf нет с PostgreSQL 12, и если положить такой файл, сервер просто не стартует. Много старых статей до сих пор советуют именно его.

recovery_target_action тоже не формальность. По умолчанию там pause: сервер доходит до нужного момента и встаёт на паузу, ожидая вашего решения. Со значением promote он сразу начинает принимать нагрузку.

Это называется PITR, восстановление на точку во времени. Именно оно спасает в сценарии «в 14:30 выполнили не тот DELETE»: вы поднимаете базу на 14:29 и теряете минуту вместо суток.

RPO при таком раскладе равен интервалу архивации журнала, то есть минутам, а не времени между полными бэкапами.

MySQL: то же самое другими словами

Логический дамп: mysqldump --single-transaction (для InnoDB снимает согласованный снимок без блокировки таблиц). Согласованность ломается, если параллельно с дампом идёт DDL по выгружаемым таблицам.

Физическая копия: для MySQL и Percona Server это Percona XtraBackup, для MariaDB — mariadb-backup (раньше называлась mariabackup). Это разные инструменты, а не синонимы: XtraBackup 8.4 с MariaDB не работает вовсе.

Аналог WAL: бинарный лог, binlog. С ним точно так же доступно восстановление на точку во времени.

Что выбирать

Небольшая база, RTO в часах: хватает логического дампа по расписанию. Просто, переносимо, легко проверяется.

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

Реплика в схеме не заменяет ни то, ни другое: она повторит ошибочный запрос за миллисекунды.

Проверка: развернуть и посчитать

Дамп базы проверяется только разворачиванием. Минимальный автоматический тест выглядит так: поднять пустой экземпляр, восстановить копию, сравнить количество строк в ключевых таблицах с ожидаемым, погасить.

createdb checkdb
pg_restore -d checkdb latest.dump
psql -d checkdb -c "select count(*) from orders;"

createdb тут обязателен: pg_restore сам базу не создаёт.

Такой прогон раз в неделю ловит и битые архивы, и сюрпризы вида «таблицу исключили из дампа год назад и забыли».

Что важно запомнить

Копировать файлы работающей базы обычным cp нельзя: получится набор файлов из разных моментов.

Логический дамп переносим и позволяет достать отдельные таблицы, но медленно восстанавливается.

Физический бэкап быстрее и служит основой для PITR, но привязан к версии и платформе.

Архив WAL (в MySQL — binlog) даёт восстановление на точку во времени и опускает RPO до минут.

Дамп считается рабочим только после разворачивания и проверки данных.

Дальше практика: файловые бэкапы через restic, с реальными командами и выводом.

Прошли материал до конца? Отметьте урок пройденным.