Резервное копирование PostgreSQL: создание копии, хранение и проверка восстановления
Чтобы настроить резервное копирование PostgreSQL, выберите способ создания копии, сохраняйте архивы вне основного сервера и регулярно восстанавливайте их в отдельной тестовой базе. Для небольшого приложения часто достаточно ежедневного логического дампа через pg_dump. Если потеря даже нескольких часов данных недопустима, понадобятся физические резервные копии и архивирование WAL. В обоих случаях важнее всего проверка восстановления: наличие файла ещё не гарантирует, что приложение удастся запустить после сбоя.
Опубликовано: · Обновлено:

Что нужно защитить и как часто делать копии
Сначала определите два показателя. RPO (Recovery Point Objective) — допустимый объём потери данных, выраженный во времени. RTO (Recovery Time Objective) — допустимое время восстановления работы. Например, если RPO равен 24 часам, ежедневный успешный дамп может соответствовать задаче. При RPO в пять минут одних суточных дампов недостаточно.
Учитывайте не только размер базы. В приложении могут быть загруженные файлы, секреты, миграции, конфигурации, фоновые очереди и внешние сервисы. Дамп PostgreSQL их автоматически не сохранит. Для согласованного восстановления может потребоваться отдельная копия файлового хранилища и запись версии приложения.
Пример конфигурации для небольшого проекта, а не универсальный минимум: один PostgreSQL на VPS с 2 виртуальными CPU, 4 ГБ оперативной памяти и базой до нескольких гигабайт; ежедневный логический дамп, несколько недель хранения и тест восстановления раз в месяц. Реальные ресурсы зависят от нагрузки, объёма индексов, скорости диска и допустимого времени простоя.
Логический дамп или физическая копия с WAL
Логический дамп экспортирует структуру и данные в SQL либо специальный архив. Физическая копия сохраняет файлы всего кластера PostgreSQL. WAL (Write-Ahead Log, журнал предзаписи) фиксирует изменения и позволяет воспроизводить их поверх подходящей базовой копии. PITR (Point-in-Time Recovery, восстановление на момент времени) даёт возможность остановить воспроизведение на выбранной точке, например перед ошибочной операцией.
Логические копии: pg_dump и pg_restore
Подход удобен для одной базы, небольших проектов, переноса схемы и выборочного восстановления объектов. pg_dump создаёт согласованный снимок при работающем сервере и обычно не блокирует обычные чтения и записи. Минусы: восстановление крупных баз может быть длительным; журналы WAL не входят в дамп, поэтому получить произвольное состояние между двумя выгрузками нельзя.
Физическая копия и непрерывный архив WAL
Для строгих требований к RPO и большим базам используйте pg_basebackup или специализированные средства, например pgBackRest и WAL-G, с архивированием WAL. Сохранить нужно и корректную базовую копию, и всю цепочку необходимых WAL-сегментов. Разрыв цепочки ограничивает или делает невозможным восстановление на нужный момент. Физическая копия восстанавливает кластер целиком и обычно требует совместимой основной версии PostgreSQL, поэтому она менее удобна для переноса одной таблицы или обновления на новую основную версию.
Не путайте резервную копию с репликой: ошибочное удаление таблицы и другие логические изменения могут повториться на реплике. Снимок диска VPS без согласования с PostgreSQL и учёта WAL тоже не следует считать автоматически проверенной копией. Управляемые базы могут предоставлять собственные бэкапы и PITR, но срок хранения, доступ к скачиванию и процедура восстановления зависят от конкретного тарифа.
Как создать дамп PostgreSQL
Подготовьте доступ и проверьте версии
Примеры далее рассчитаны на Linux и оболочку Bash. Замените db.example.internal, appdb, backup_user, localhost и путь /srv/pg-backups на свои значения. Выдавайте пользователю резервного копирования только необходимые права чтения и подключения. Для полного дампа нужны права на все сохраняемые объекты; иначе операция может завершиться ошибкой. Пароль не помещайте в команды и историю оболочки: используйте защищённый файл .pgpass с правами 0600 или другой механизм управления секретами.
pg_dump --version
psql -h db.example.internal -U backup_user -d appdb -Atqc 'SHOW server_version;'Основная версия pg_dump не должна быть старше основной версии сервера: более старый клиент откажется выгружать новую версию PostgreSQL. Предпочтительно использовать утилиты той же основной версии, что и сервер, и отдельно проверить восстановление в целевой версии. Перенос дампа на более старую основную версию не гарантируется. Команды ниже предполагают, что подключение и авторизация уже настроены.
Создайте архив в формате custom
Формат custom (-Fc) даёт сжатый архив и позволяет применять pg_restore, в том числе для выборочного восстановления. Подготовьте каталог, доступный только учётной записи бэкапов. Пример разового создания:
install -d -m 700 /srv/pg-backups
pg_dump -h db.example.internal -U backup_user -d appdb \
-Fc -f /srv/pg-backups/appdb-2026-10-14.dump
pg_restore --list /srv/pg-backups/appdb-2026-10-14.dump | headКоманда pg_restore --list проверяет возможность прочитать оглавление архива, но не доказывает, что все данные исправны или восстановятся. Обычный текстовый SQL можно сделать через pg_dump -Fp; восстанавливают его утилитой psql, а не pg_restore. Для параллельной выгрузки большого объёма предусмотрен формат directory (-Fd) с параметром -j, который открывает дополнительные соединения и нагружает сервер.
Сохраните роли и учтите расширения
pg_dump выгружает только одну базу. Роли, а также другие глобальные объекты кластера не включаются. Администратор с соответствующими правами может отдельно сохранить их командой ниже. Полученный SQL-файл может содержать чувствительные сведения, включая хеши паролей ролей; ограничьте доступ и шифруйте его.
pg_dumpall -h db.example.internal -U postgres \
--globals-only -f /srv/pg-backups/globals-2026-10-14.sqlНа тестовом сервере заранее создайте нужные роли либо при пробном восстановлении используйте --no-owner --no-acl, понимая, что проверка исходной модели владения и прав в этом случае не выполняется. Расширения, например PostGIS или pg_trgm, требуют совместимого программного окружения и доступных пакетов на целевой стороне. Проверьте их список до восстановления:
psql -h db.example.internal -U backup_user -d appdb \
-c 'SELECT extname, extversion FROM pg_extension ORDER BY extname;'Некоторые приложения зависят от объектов вне дампа: настроек сервера, фоновых воркеров, сертификатов, cron-задач и файлов. Ведите отдельный перечень таких зависимостей. Не восстанавливайте SQL из недоверенного источника без проверки: дамп может содержать команды, исполняемые с правами пользователя восстановления.
Как хранить копии и ограничивать ущерб
Практичный подход — правило 3-2-1: три экземпляра данных, два типа или независимых места хранения и хотя бы одна копия вне исходного сервера. Это ориентир, а не формальная гарантия. Если бэкап находится лишь на том же VPS, отказ диска, взлом или удаление виртуальной машины могут уничтожить и базу, и архив.
Пример организации каталогов: локальный временный /srv/pg-backups/appdb/; затем отдельный сервер или объектное хранилище с каталогами daily/, weekly/ и monthly/. Имена включают имя базы и метку времени в UTC, например appdb-20261014T030000Z.dump. Вместе с ними храните контрольную сумму SHA-256, запись версии PostgreSQL и результат последнего теста восстановления.
sha256sum /srv/pg-backups/appdb-2026-10-14.dump \
> /srv/pg-backups/appdb-2026-10-14.dump.sha256
cd /srv/pg-backups && sha256sum -c appdb-2026-10-14.dump.sha256Передавайте архивы по защищённому каналу, включите шифрование при хранении и разделите права: приложение не должно иметь возможности удалять резервные копии. По возможности используйте неизменяемое хранение или отдельные учётные данные с ограничением на удаление. Ключи шифрования и инструкции восстановления храните отдельно, иначе при утрате ключа копия окажется бесполезной.
Политика хранения зависит от RPO, RTO, требований бизнеса и объёма данных. Например, можно сохранять семь ежедневных, четыре еженедельных и несколько ежемесячных копий. Это только пример, а не обязательный график. Учитывайте стоимость места, запросов, исходящего трафика и операций восстановления; проверьте лимиты поставщика. Для PITR срок хранения WAL должен соответствовать нужному окну восстановления, а удаление старых базовых копий и журналов должно быть согласовано.
Автоматизация, журнал ошибок и уведомления
Задание должно завершаться ошибкой, если pg_dump не удался, архив пуст, проверка формата провалилась или передача во внешнее хранилище завершилась неуспешно. Недостаточно запускать команду по расписанию и считать наличие файла успехом. Ниже пример локального скрипта без внешней выгрузки: её следует добавить отдельным проверяемым шагом до удаления временного файла.
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
DIR=/srv/pg-backups/appdb
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
TMP="$DIR/.appdb-$STAMP.dump.tmp"
OUT="$DIR/appdb-$STAMP.dump"
mkdir -p "$DIR"
trap 'rm -f "$TMP"' EXIT
pg_dump -h db.example.internal -U backup_user -d appdb -Fc -f "$TMP"
test -s "$TMP"
pg_restore --list "$TMP" >/dev/null
mv "$TMP" "$OUT"
sha256sum "$OUT" > "$OUT.sha256"
printf 'Backup created: %s\n' "$OUT"Запускайте скрипт под отдельной системной учётной записью. Убедитесь, что каталог заранее имеет права только для неё. Для cron пример расписания ежедневного запуска в 03:15 по часовому поясу сервера: 15 3 * * * /usr/local/sbin/backup-appdb.sh. Поскольку cron использует окружение, отличное от интерактивной оболочки, задайте нужные пути и переменные, а также продумайте запрет параллельных запусков через flock. Проверяйте код выхода, ведите журнал с ограниченным доступом, уведомляйте об ошибках и об отсутствии свежего успешного бэкапа.
Передача копии во внешнее хранилище должна иметь собственную проверку успешной загрузки, размера или контрольной суммы. Ротацию запускайте только после подтверждения сохранности новых копий. Полезно отслеживать рост размера дампов, длительность выгрузки, свободное место и возраст последней проверенной копии.
Проверка восстановления в отдельной среде
Следующие команды никогда не обращаются к рабочей базе в качестве получателя. Подготовьте отдельный тестовый экземпляр PostgreSQL на localhost:5433. Это должен быть изолированный сервер с подходящей версией и необходимыми расширениями. Не используйте продакшен-порт и не подключайте тестовое приложение к реальным внешним интеграциям: триггеры, задания и обработчики могут вызвать побочные действия.
Создайте новую тестовую базу
Для упрощённой проверки игнорируем владельцев и исходные ACL (Access Control List, списки прав доступа). Для полной проверки прав необходим второй тест с восстановлением ролей и назначений на изолированном сервере. Важно: не используйте --create и --clean для этих команд — они здесь не нужны.
createdb -h localhost -p 5433 -U restore_user \
-T template0 appdb_restore_test
pg_restore -h localhost -p 5433 -U restore_user \
-d appdb_restore_test --no-owner --no-acl \
--exit-on-error /srv/pg-backups/appdb-2026-10-14.dumpПараметр --exit-on-error останавливает восстановление при первой SQL-ошибке. Пользователь restore_user должен иметь достаточные права на создание объектов в пустой базе; для некоторых расширений могут потребоваться дополнительные права или предварительная установка. Для больших дампов дополнительно оценивайте скорость восстановления и занимаемое пространство: RTO определяется временем реальной процедуры, а не размером файла.
Проверьте данные и приложение
psql -h localhost -p 5433 -U restore_user -d appdb_restore_test \
-v ON_ERROR_STOP=1 -c 'SELECT current_database(), now();'
psql -h localhost -p 5433 -U restore_user -d appdb_restore_test \
-v ON_ERROR_STOP=1 -c 'SELECT count(*) FROM pg_catalog.pg_tables WHERE schemaname NOT IN ('pg_catalog','information_schema');'Количество таблиц — только базовая проверка. Сравните контрольные записи, объёмы ключевых таблиц, ограничения, последовательности, представления и расширения. Запустите приложение в тестовом контуре без отправки писем, платежей и вебхуков. После восстановления выполните ANALYZE для обновления статистики планировщика, если это требуется вашим сценарием. Зафиксируйте дату, использованный архив, длительность, результат и замечания. При необходимости тестовую базу удаляют только после проверки имени и адреса тестового сервера.
Как проверить физические копии и PITR
Для физической схемы одного успешного pg_basebackup недостаточно. Убедитесь, что архивирование WAL действительно работает, базовые копии доступны отдельно от исходного сервера, цепочка журналов непрерывна и пространство под ними контролируется. Утилита pg_verifybackup проверяет манифест и файлы подходящей базовой копии, созданной pg_basebackup; возможности проверки WAL зависят от формата архива и версии утилиты.
Полноценный тест PITR проводят на отдельном экземпляре или изолированном узле: берут базовую копию, обеспечивают доступ к необходимым WAL, устанавливают целевой момент восстановления и проверяют старт кластера и данные. Не направляйте процедуру на действующий каталог данных. Специальные средства pgBackRest и WAL-G позволяют организовать политику копий, архивирование и восстановление, но их конфигурация, права, совместимость и команды зависят от используемых версий; перед внедрением выполните тест по выбранному инструменту.
Частые ошибки резервного копирования
- Копии лежат только на том же VPS, что и PostgreSQL.
- Проверяют лишь размер архива, но никогда не запускают pg_restore.
- Сохраняют одну базу и забывают о ролях, расширениях и внешних файлах.
- Не замечают сбой cron, истечение срока действия ключа или заполнение диска.
- Включают PITR, но не контролируют непрерывность и срок хранения WAL.
- Восстанавливают архив в рабочую базу вместо изолированной среды.
- Шифруют копии, но теряют ключи либо не проверяют доступ к ним.
Короткий план внедрения
Начните с определения RPO и RTO, выберите логические дампы либо физическую схему с WAL, выдайте минимально необходимые права, сохраните роли и перечень расширений, автоматизируйте выгрузку и безопасную передачу вне исходного VPS. Затем настройте контроль ошибок и сроки хранения. Завершённой систему можно считать только после успешного восстановления в отдельной среде с проверкой данных и запуска приложения.