# Backup и восстановление на точку (PITR) _Эксплуатация и наблюдаемость · PostgreSQL Knowledge Base_ **TL;DR:** Планируй восстановление, а не бэкап. pg_dump делает логический снимок на один момент. PITR строится из базовой физической копии (pg_basebackup) плюс непрерывного архива WAL: можно восстановиться на любой момент между копией и «сейчас» - в том числе на секунду до ошибочного DROP. ## Вопрос не «есть ли бэкап», а «что я смогу восстановить» Бэкап без проверенного восстановления - это надежда, а не страховка. Поэтому отталкиваются от цели: на какой момент и как быстро нужно уметь вернуться. Под разные ответы - разные инструменты. ## pg_dump: логический снимок `pg_dump` обходит базу одной транзакцией и выгружает её содержимое (схему и/или данные) как SQL или в своём формате. Свойства: - снимок строго на момент начала дампа, ни секундой позже; - переносим между мажорными версиями и архитектурами; - медленно восстанавливается на больших базах (это перезаливка данных и перестройка индексов); - нельзя «докрутить» до состояния через 10 минут после дампа. Это резервная копия уровня логики. Для «вернуть вчерашнюю базу целиком» годится; для «вернуть на 14:59, за минуту до аварии» - нет. ## PITR: базовая копия + архив WAL Point-in-time recovery собирается из двух частей: 1. **Базовая копия** - физический слепок кластера на некоторый момент. Снимается `pg_basebackup` прямо с работающего сервера. 2. **Непрерывный архив WAL** (см. [wal](/courses/postgres/kb/wal.md)) - сервер с `archive_mode = on` отдаёт каждый заполненный сегмент журнала командой `archive_command` в надёжное место. ``` база на T0 ──┐ ├──▶ восстановление: разворачиваем копию, WAL: T0 ─────▶ T1 ─────▶ T2 ─────▶ now проигрываем WAL до recovery_target_time ``` Имея копию на T0 и весь WAL после неё, можно развернуть копию и проиграть журнал ровно до нужной точки - по времени (`recovery_target_time`), по LSN или по именованной точке. Сервер стартует с `recovery.signal` и `restore_command`, который подаёт ему архивные сегменты, и останавливает replay на цели. ## Классический сценарий «спасли от DROP» В 15:00 кто-то выполнил `DROP TABLE orders`. Есть базовая копия с ночи и архив WAL. Восстановление: 1. развернуть ночную копию в отдельный каталог; 2. задать `recovery_target_time = '15:00:00 минус секунда'`; 3. дать `restore_command`, чтобы сервер тянул архивные сегменты; 4. поднять - сервер проиграет WAL до момента перед DROP и остановится. Таблица на месте, всё после рокового момента - откатано. Этого `pg_dump` не умеет в принципе. ## archive_mode требует рестарта Частая засада: `archive_mode` нельзя включить на лету. Это параметр уровня сервера, он применяется только при рестарте - в отличие от `archive_command`, который перечитывается по reload. Включать архив нужно заранее, а не в момент, когда копия уже понадобилась. ```sql -- архив включён? применился ли (а не ждёт рестарта)? SELECT name, setting, pending_restart FROM pg_settings WHERE name IN ('archive_mode', 'archive_command'); ``` Что физически копируется - это форки ([relfilenode-forks](/courses/postgres/kb/relfilenode-forks.md)) и сегменты WAL; механика replay - та же, что crash recovery ([checkpoint](/courses/postgres/kb/checkpoint.md)), только цель задаётся явно. ## Команды ```sql pg_basebackup -D /backup/base -X stream -c fast ``` Снять базовую физическую копию с работающего сервера ```sql SELECT name, setting, pending_restart FROM pg_settings WHERE name LIKE 'archive%'; ``` Включён ли архив WAL и применился ли (или ждёт рестарта) ```sql SELECT pg_walfile_name(pg_current_wal_lsn()); ``` Имя текущего сегмента WAL - привязка момента к архиву ```sql pg_dump -Fc lab > lab.dump ``` Логический снимок базы на момент начала дампа (custom-формат) ## См. также - [Карта pg_stat_* и pg_stat_statements](/courses/postgres/kb/pg-stat-map.md) - [Конфигурация памяти в контексте механизма](/courses/postgres/kb/memory-config.md) - [Каталог анти-паттернов (cheat sheet)](/courses/postgres/kb/anti-patterns.md) - [WAL: принцип write-ahead и LSN](/courses/postgres/kb/wal.md) - [Контрольные точки и восстановление](/courses/postgres/kb/checkpoint.md)