Резервное копирование PostgreSQL — это не только pg_dump. Важно выбрать формат под задачу, настроить архивацию WAL, автоматизировать выгрузку и регулярно проверять восстановление. Разберём рабочую схему для домашнего сервера и небольшой производственной базы.
Способы копирования
Логическое копирование (pg_dump) даёт переносимый дамп между версиями. Физическое (резервные копии каталога данных через pg_basebackup) быстрее для больших баз, но привязано к версии.
# логическая копия одной базы
pg_dump -Fc -Z6 -f /backup/mydb.dump mydb
# все базы
pg_dumpall --globals-only > /backup/globals.sql
pg_dumpall > /backup/all.sql
# проверить дамп
ls -lh /backup/mydb.dump
pg_restore --list /backup/mydb.dump | head -10
Формат -Fc (custom) сжат и поддерживает частичное восстановление через pg_restore — это практичнее обычного SQL-файла.
Автоматизация через cron
#!/bin/bash
# /usr/local/bin/pg-backup.sh
set -euo pipefail
BACKUP_DIR=/backup/postgresql
DATE=$(date +%F_%H-%M)
mkdir -p "$BACKUP_DIR"
for db in $(psql -At -c "SELECT datname FROM pg_database WHERE NOT datistemplate"); do
pg_dump -Fc -f "$BACKUP_DIR/${db}_${DATE}.dump" "$db"
done
# оставить последние 14 дней
find "$BACKUP_DIR" -name '*.dump' -mtime +14 -delete
# crontab -e
# 30 3 * * * /usr/local/bin/pg-backup.sh >> /var/log/pg-backup.log 2>&1
Переменные подключения задавайте через PGHOST, PGUSER, PGPASSWORD в защищённом файле, а не прямо в скрипте.
Архивация WAL для точного восстановления
Чтобы восстановиться не на момент дампа, а на любую секунду, включите архивацию WAL.
# postgresql.conf
# wal_level = replica
# archive_mode = on
# archive_command = 'cp %p /backup/wal/%f'
psql -c "show wal_level;"
psql -c "show archive_mode;"
ls /backup/wal | wc -l
Архивировать можно и на удалённый сервер: rsync, объектное хранилище или отдельная машина. Главное — не хранить архив на том же диске, что и база.
Проверка восстановления
Непроверенная копия не считается копией. Восстановление тестируют на изолированной машине или в контейнере.
# восстановление в отдельную базу
createdb restore_test
pg_restore -d restore_test /backup/mydb.dump
# сверка
psql -d restore_test -Atc "select count(*) from important_table"
psql -d mydb -Atc "select count(*) from important_table"
# очистка
dropdb restore_test
Планируйте проверку раз в месяц и записывайте время восстановления: оно и есть ваш реальный RTO.
Репликация как дополнение
Стандбай-реплика — не замена бэкапу, но способ сократить потерю данных до секунд при отказе основного сервера.
# на реплике
pg_basebackup -D /var/lib/postgresql/16/main -Fp -Xs -R
# в standby.signal и postgresql.auto.conf задаётся primary_conninfo
# проверить роль
psql -Atc "select pg_is_in_recovery();"
Хранение и шифрование
# сжатие уже есть в -Fc; для каталогов
tar -czf /backup/wal-$(date +%F).tar.gz /backup/wal
# шифрование архива (пример gpg)
gpg --symmetric --cipher-algo AES256 /backup/mydb.dump
# выгрузка на другой хост
rsync -av /backup/postgresql/ backup@nas:/backups/pg/
Держите минимум три копии на двух разных носителях, одна — вне площадки. И храните пароль шифрования отдельно от данных.
Мониторинг заданий
# последний запуск и его результат
tail -20 /var/log/pg-backup.log
# размер выгрузок
du -sh /backup/postgresql
# не вырос ли WAL из-за сломанного archive_command
psql -Atc "select count(*) from pg_stat_archiver;"
Остановленный архиватор — классический сценарий: база перестаёт принимать запись, потому что WAL не удаляются.
Что бэкапить кроме самих данных
Дамп базы не содержит ролей, tablespaces и части конфигурации. При восстановлении на чистый сервер это вылезет в ручную работу.
# роли и глобальные настройки
pg_dumpall --globals-only > /backup/globals.sql
# конфигурацию сервера
sudo cp -a /etc/postgresql /backup/etc-postgresql-$(date +%F)
# сертификаты и ключи, если используются TLS
sudo tar -czf /backup/pg-ssl-$(date +%F).tar.gz /var/lib/postgresql/*/main/ssl 2>/dev/null || true
# сверить состав
ls -lh /backup/
Храните рядом с копиями и версии: версию PostgreSQL, список расширений и версии пакетов. Восстановление дампа на другую мажорную версию часто требует промежуточного шага.
# версии и расширения
psql -Atc "select version();"
psql -Atc "select extname, extversion from pg_extension;"
Планирование RTO и RPO
RPO — сколько данных вы готовы потерять, RTO — сколько времени готовы восстанавливаться. От них зависит выбор метода.
- RPO часы — достаточно ежедневного
pg_dump. - RPO минуты — нужна архивация WAL.
- RTO минуты — нужен готовый сервер или реплика.
# оценить фактическое окно потери данных
# дата последнего дампа
ls -l --time-style=long-iso /backup/postgresql | tail -5
# количество архивных WAL
ls /backup/wal | wc -l
Запишите выбранные значения рядом с процедурой восстановления: без них любая инструкция остаётся мнением.
Восстановление после сбоя: порядок действий
- Поднять чистый кластер той же версии.
- Восстановить роли из
globals.sql. - Восстановить последний дамп нужной базы.
- Применить архив WAL до нужного момента.
- Сверить критичные таблицы контрольными запросами.
- Переключить приложение и наблюдать за логами.
# контрольные сверки
psql -Atc "select count(*) from orders;"
psql -Atc "select max(created_at) from orders;"
# журналы после переключения
journalctl -u postgresql -b | tail -30
Типичные ошибки бэкапов
- Задание написано, но лог пуст: ошибка авторизации, которая молча проглатывается без
set -e. - Дампы пишутся на тот же диск, что и база, — общий отказ не переживёт ни данные, ни копии.
- Ретеншн слишком агрессивный: старые копии удаляются раньше, чем обнаруживается порча данных.
- Восстановление никогда не тестировалось, и объём таблицы в дампе отличается от ожидаемого.
- Пароль от шифрования архива лежит рядом с ним же.
# убедиться, что задание реально отработало
grep -c "pg_dump" /var/log/pg-backup.log | tail -1
ls -lh --time-style=long-iso /backup/postgresql | tail -5
# сверить размеры за последние запуски — резкий обвал подозрителен
du -sh /backup/postgresql/* 2>/dev/null | tail -5
Итог
Рабочая схема: pg_dump -Fc по cron, архивация WAL, выгрузка копий на другой хост и ежемесячная проверка восстановления. Репликация сокращает потерю данных, но не заменяет бэкап. Фиксируйте RTO и RPO на практике, а не в планах.