Восстановление PostgreSQL на момент времени (PITR) через WAL
Продвинутое3 минРедакция Innovialabs
Коротко
PITR восстанавливает базовый бэкап и проигрывает архивные WAL-файлы до выбранного момента, поэтому базу можно вернуть на секунду до ошибочного DELETE; для этого нужна непрерывная архивация WAL и регулярные тестовые восстановления.
Коротко
PostgreSQL записывает каждое изменение в журнал предзаписи (WAL) до того, как применить его к файлам данных. Если у вас есть:
- базовый бэкап (физическая копия каталога данных) и
- все сегменты WAL, созданные после этого бэкапа,
можно восстановить бэкап и проиграть WAL до любого выбранного момента. Это и есть восстановление на момент времени (PITR). Ночной pg_dump так не умеет: он возвращает только к моменту дампа.
Писать скрипты для archive_command вручную ненадёжно, поэтому обычно используют pgBackRest или WAL-G. Оба берут на себя сжатие, хранение по политике retention, параллельность и работу с локальным репозиторием или объектным хранилищем вроде S3.
Настройка pgBackRest
Конфигурация PostgreSQL (postgresql.conf):
wal_level = replica
archive_mode = on
archive_command = 'pgbackrest --stanza=main archive-push %p'
Для archive_mode нужен перезапуск. Затем конфиг pgBackRest (/etc/pgbackrest/pgbackrest.conf):
[global]
repo1-path=/var/lib/pgbackrest
repo1-retention-full=2
[main]
pg1-path=/var/lib/postgresql/data
Инициализируйте, проверьте и сделайте первый полный бэкап:
pgbackrest --stanza=main stanza-create
pgbackrest --stanza=main check
pgbackrest --stanza=main --type=full backup
Запускайте бэкапы по расписанию через cron или systemd timer, например полный раз в неделю и дифференциальный ежедневно (--type=diff). Храните репозиторий на другой машине или в объектном хранилище: бэкап на том же диске погибнет вместе с сервером.
Альтернатива: WAL-G
WAL-G настраивается через переменные окружения (префикс хранилища, ключи доступа, сжатие) и хорошо работает с облачными хранилищами:
archive_command = 'wal-g wal-push %p'
wal-g backup-push "$PGDATA"
Выбор в основном про эксплуатацию: у pgBackRest богатая проверка целостности и режим локального репозитория, WAL-G лёгкий и ориентирован на облако. PITR поддерживают оба.
Восстановление после случайного удаления
Допустим, кто-то выполнил DELETE FROM orders без WHERE около 14:30.
1. Определите целевое время. Используйте логи приложения, лог PostgreSQL (если log_statement это фиксирует) или pg_waldump, чтобы найти транзакцию. Выберите момент прямо перед удалением. Если известен ID транзакции или LSN, точнее будут recovery_target_xid или recovery_target_lsn.
2. Лучше восстанавливать на отдельный сервер. Тогда потерянные строки можно перенести обратно в продакшен, не откатывая всё остальное, что произошло после 14:30.
3. Восстановление через pgBackRest:
sudo systemctl stop postgresql
pgbackrest --stanza=main --delta \
--type=time "--target=2026-10-10 14:29:00+05" \
--target-action=promote restore
sudo systemctl start postgresql
pgBackRest сам прописывает параметры восстановления. С WAL-G вы скачиваете бэкап и задаёте их вручную:
wal-g backup-fetch "$PGDATA" LATEST
touch "$PGDATA/recovery.signal"
restore_command = 'wal-g wal-fetch %f %p'
recovery_target_time = '2026-10-10 14:29:00+05'
recovery_target_action = 'promote'
4. Проверьте результат, прежде чем куда-то его переносить: количество строк, последние записи до инцидента, смоук-тесты приложения. Если момент выбран неудачно, восстановите заново с другой целью.
После восстановления PostgreSQL начинает новую линию времени (timeline). Вскоре сделайте свежий полный бэкап.
Как тестировать процедуру
Бэкап, который вы ни разу не восстанавливали, — это надежда, а не бэкап. Сделайте проверку рутиной:
- Восстанавливайте на отдельный сервер по расписанию, а не только во время инцидентов.
- Запускайте
pgbackrest checkили следите заpg_stat_archiverна предмет неудачных попыток архивации. - Настройте алерт на отставание или сбой архивации: диск, забитый неархивированными WAL, может остановить основной сервер.
- Замерьте, сколько длится восстановление. Это ваше реальное время восстановления, и оно растёт с объёмом данных и количеством WAL для проигрывания.
- Напишите короткий runbook с точными командами, чтобы в стрессе восстановление сводилось к копированию.
Частые ошибки
- Хранить бэкапы на том же сервере или диске, что и базу.
- Включить архивацию и ни разу не проверить, что она проходит.
- Слишком короткий retention, который не покрывает период, когда ошибки обычно замечают.
- Восстанавливать прямо поверх продакшена и терять легитимные изменения после инцидента.
- Забывать про часовой пояс в целевом времени.