Бекап PostgreSQL через pg_probackup

Лабораторные работы

ОС: Debian 13 (Trixie)
Версия PostgreSQL: 18
Стратегия: FULL-бэкап каждую субботу, PAGE-инкремент в остальные дни.
Хранение: 4 FULL-цепочки (≈ 4 недели) с WAL для каждой.


Установка

apt install -y gpg wget

wget -qO - https://repo.postgrespro.ru/pg_probackup/keys/GPG-KEY-PG-PROBACKUP | \
  tee /etc/apt/trusted.gpg.d/pg_probackup.asc

. /etc/os-release
echo "deb [arch=amd64] https://repo.postgrespro.ru/pg_probackup/deb $VERSION_CODENAME main-$VERSION_CODENAME" | \
  tee /etc/apt/sources.list.d/pg_probackup.list

apt update && apt install pg-probackup-18

Каталоги

В реальной ситуации используйте для бекапа NFS. Нам понадобится папка бекапа и папка для логов работы бекапов.

mkdir -p /mnt/nfs/backup
chown postgres:postgres /mnt/nfs/backup

mkdir -p /var/log/pgbackup
chown postgres:postgres /var/log/pgbackup

Теперь надо инициализировать pg_probackup, указав ему созданные папки.

su - postgres

pg_probackup-18 init -B /mnt/nfs/backup

pg_probackup-18 add-instance \
  -B /mnt/nfs/backup \
  --instance main \
  --pgdata /var/lib/postgresql/18/main

Настройка PostgreSQL

Для работы резервного копирования необходимо внести правки в postgresql.conf:

wal_level = replica
archive_mode = on
archive_timeout = 300
archive_command = 'pg_probackup-18 archive-push -B "/mnt/nfs/backup" --instance "main" --wal-file-path=%p --wal-file-name=%f --compress'

wal_level = replica — Определяет количество информации, записываемой в WAL. Уровень replica пишет достаточно данных для восстановления и репликации. Это минимально необходимый уровень при archive_mode = on.
archive_mode = on — Включает механизм архивирования WAL. При on — каждый заполненный сегмент передаётся в archive_command перед тем как может быть удалён.
archive_timeout = 300 — Принудительно переключает текущий сегмент каждые 5 минут, даже если он не заполнен. Иначе PostgreSQL будет ждать накопления определённого объёма, что на малых базах может занимать часы. Значение 300 гарантирует, что мы не потерям данных больше, чем за 5 минут (RPO 5 минут).
archive_command = '...' — Команда, которую PostgreSQL выполняет для каждого готового WAL-сегмента до его удаления.

pg_probackup-18 archive-push — подкоманда pg_probackup, которая принимает WAL-сегмент и кладёт его в каталог бэкапов.
-B "/mnt/nfs/backup" — путь к корневому каталогу бэкапов (backup catalog), тот же что указан во всех остальных командах pg_probackup.
--instance "main" — имя инстанса, которое мы задали при add-instance. WAL ляжет в wal/main/ внутри каталога бэкапов.
--wal-file-path=%p — %p подставляется PostgreSQL и содержит полный путь к файлу сегмента на диске, например /var/lib/postgresql/18/main/pg_wal/000000010000000000000001. Это источник — откуда взять файл.
--wal-file-name=%f%f подставляется PostgreSQL и содержит только имя файла, например 000000010000000000000001. Это имя, под которым файл будет сохранён в архиве.
--compress — сжимать WAL-сегменты при сохранении в архив. Алгоритм берётся из set-config (настроим дальше). Экономит место.

Так же нам необходима роль в PostgreSQL для создания бекапов с набором прав (обратите внимание, для версий ниже PostgreSQL 15 запросы будут другие):

CREATE ROLE backup WITH LOGIN;

GRANT USAGE ON SCHEMA pg_catalog TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_backup_start(text, boolean) TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_backup_stop(boolean) TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_create_restore_point(text) TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_switch_wal() TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_last_wal_replay_lsn() TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_current() TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_checkpoint() TO backup;

Добавим доверие для локального подключения в pg_hba.conf:

local   all     backup                      peer

Применим настройки, перезагрузив PostgreSQL:

systemctl restart postgresql

Проверяем архивацию WAL — в папке должны появиться файлы:

su - postgres -c "psql -c \"SELECT pg_switch_wal();\""
ls /var/lib/pgbackup/wal_archive/main/wal/

Конфигурация pg_probackup

su - postgres

pg_probackup-18 set-config \
  -B /mnt/nfs/backup \
  --instance main \
  --retention-redundancy=4 \
  --wal-depth=4 \
  --compress-algorithm=zlib \
  --compress-level=1 \
  --archive-timeout=15min \
  --log-level-console=INFO \
  --log-level-file=WARNING \
  --log-filename=pg_probackup.log \
  --error-log-filename="error-pg_probackup-%u.log" \
  --log-directory=/var/log/pgbackup \
  --log-rotation-age=7d

-B /mnt/nfs/backup — Путь к корневому каталогу бэкапов. Должен совпадать во всех командах pg_probackup.
--instance main — Имя инстанса, для которого сохраняется конфиг. Один каталог может хранить бэкапы нескольких инстансов с разными именами.
--retention-redundancy=4 — Сколько FULL-бэкапов хранить. Когда после очередного FULL их становится 5 — самый старый удаляется вместе со всей своей цепочкой PAGE-инкрементов.
--wal-depth=4 — Для скольких последних FULL-цепочек хранить WAL в архиве. Совпадает с retention-redundancy=4 — WAL хранится ровно для тех цепочек, которые ещё не удалены. WAL старше самого старого хранимого FULL удаляется.
--compress-algorithm=zlib — Алгоритм сжатия бэкапов и WAL-архива.
--compress-level=1 — Уровень сжатия от 1 до 19 для zstd. Уровень 1 — минимальное сжатие, максимальная скорость. Это обеспечит разумное уменьшение объём при высокой скорости выполнения бекапа.
--archive-timeout=15min — Сколько времени pg_probackup ждёт появления нужного WAL-сегмента в архиве во время снятия бэкапа. Актуально при медленном хранилище — например NFS, где archive_command может выполняться с задержкой. Не путать с archive_timeout в postgresql.conf — это разные параметры.
--log-level-console=INFO — Уровень детализации логов в stdout. INFO — выводить все информационные сообщения. Удобно видеть прогресс при ручном запуске.
--log-level-file=WARNING — Уровень детализации логов в файл. WARNING — писать только предупреждения и ошибки. В production нет смысла хранить подробный лог каждого успешного бэкапа — только проблемы.
--log-filename=pg_probackup.log — Имя основного лог-файла для всех сообщений уровня WARNING и выше.
--error-log-filename="error-pg_probackup-%u.log" — Отдельный файл только для ошибок. %u — маска дня недели (1=пн, 7=вс), то есть создаётся 7 файлов, которые перезаписываются каждую неделю. Удобно для мониторинга — достаточно проверять один файл текущего дня.
--log-directory=/var/log/pgbackup — Каталог для всех лог-файлов pg_probackup. Вынесен отдельно от каталога бэкапов, что правильно — логи и данные не должны мешать друг другу.
--log-rotation-age=7d — Ротация лог-файлов раз в 7 дней. Без этого pg_probackup.log будет расти бесконечно. В сочетании с %u в имени файла ошибок даёт аккуратное хранение логов за неделю.

Проверяем:

pg_probackup-18 show-config -B /mnt/nfs/backup --instance main

Теперь настроим Cron для запуска полного и инкрементного бекапа:

crontab -u postgres -e

Внесём правила:

# FULL — каждую субботу в 02:00
0 2 * * 6  pg_probackup-18 backup -B /mnt/nfs/backup --instance main -b FULL --temp-slot -U backup --delete-expired --delete-wal

# PAGE — воскресенье-пятница в 02:00
0 2 * * 0,1,2,3,4,5  pg_probackup-18 backup -B /mnt/nfs/backup --instance main -b PAGE --temp-slot -U backup --delete-expired --delete-wal

0 2 * * 6 — Запуск каждую субботу в 2 часа ночи.
0 2 * * 0,1,2,3,4,5 — Запуск каждый день, кроме субботы, в 2 часа ночи.
-B /mnt/nfs/backup — Путь к корневому каталогу бэкапов. Должен совпадать во всех командах pg_probackup.
--instance main — Имя инстанса, для которого сохраняется конфиг. Один каталог может хранить бэкапы нескольких инстансов с разными именами.
-b FULL — Полная копия -b PAGE — Инкрементальный бэкап: сканирует WAL-архив с момента предыдущего бэкапа и сохраняет только изменённые страницы. --temp-slot — Создаёт временный replication slot на время бэкапа, чтобы PostgreSQL не удалил нужные WAL-сегменты до их получения.
-U backup — Пользователь PostgreSQL, от имени которого pg_probackup подключается к базе. --delete-expired --delete-wal — Удалить старые бекапы и старые WAL согласно политике.


Проверка

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

# Список бэкапов и их статус
pg_probackup-18 show -B /mnt/nfs/backup --instance main

# Валидация всего каталога
pg_probackup-18 validate -B /mnt/nfs/backup --instance main

# Состояние WAL-архива
pg_probackup-18 show -B /mnt/nfs/backup --instance main --archive

Восстановление

systemctl stop postgresql

# Восстановить последний бэкап:
pg_probackup-18 restore \
  -B /mnt/nfs/backup \
  --instance main \
  --pgdata=/var/lib/postgresql/18/main \
  --recovery-target-action=promote

# PITR — восстановить на конкретный момент времени:
pg_probackup-18 restore \
  -B /mnt/nfs/backup \
  --instance main \
  --pgdata=/var/lib/postgresql/18/main \
  --recovery-target-time="2026-05-28 15:00:00" \
  --recovery-target-action=promote

systemctl start postgresql