42.1 Планируй восстановление, а не бэкап
Сместить вопрос с бэкапа на восстановление - не игра слов. Это меняет выбор инструмента. Спроси: на какой момент нужно уметь вернуться и за сколько? Ответы бывают разные:
- «вернуть вчерашнюю базу целиком» - хватит логического дампа;
- «вернуть состояние за минуту до аварии» - нужен PITR;
- «потерять не больше N секунд при падении» - это уже про синхронную репликацию, не про бэкап.
Каждый инструмент отвечает на свой класс вопросов. Дальше разберём два главных: логический дамп и PITR.
42.2 pg_dump: логический снимок на момент
pg_dump обходит базу в одной транзакции и выгружает её содержимое
(схему, данные или то и другое) как SQL или в своём custom-формате.
Благодаря снимку MVCC дамп получается согласованным на один момент -
начало дампа, ни секундой позже.
Свойства, которые определяют его применимость:
- снимок строго на момент старта, «докрутить до позже» нельзя;
- переносим между мажорными версиями и архитектурами - это способ мигрировать на новую версию;
- восстанавливается медленно на больших базах: это перезаливка данных и перестройка всех индексов с нуля.
Логический дамп хорош для «вернуть базу на вчера» и для миграций. Для «вернуть на 14:59, за минуту до рокового DROP» он бесполезен - нужного момента в нём просто нет.
42.3 PITR: базовая копия плюс непрерывный архив WAL
Point-in-time recovery собирается из двух частей, и обе нам уже знакомы по механизму журнала:
- Базовая копия - физический слепок кластера на некоторый
момент, снятый
pg_basebackupс работающего сервера. - Непрерывный архив WAL - сервер с
archive_mode = onотдаёт каждый заполненный сегмент журнала командойarchive_commandв надёжное хранилище.
база на T0 ──┐
├──▶ восстановление: разворачиваем копию,
WAL: T0 ─────▶ T1 ─────▶ T2 ─────▶ now
проигрываем WAL до recovery_target_time
Имея копию на T0 и весь WAL после неё, можно развернуть копию и
проиграть журнал ровно до нужной точки. Это тот же replay, что в
crash recovery, - только конец задаём не «до последней записи», а
явной целью: по времени (recovery_target_time), по LSN или по
именованной точке восстановления.
42.4 Сценарий: спасение от ошибочного DROP
Классика, ради которой PITR и существует. В 15:00 кто-то выполнил
DROP TABLE orders на проде. Есть ночная базовая копия и непрерывный
архив WAL. Восстановление:
- развернуть ночную копию в отдельный каталог;
- задать цель
recovery_target_time= момент перед DROP (скажем, 14:59:59); - дать
restore_command, чтобы сервер подавал себе архивные сегменты WAL; - поднять сервер - он проиграет журнал от ночной копии до 14:59:59 и остановится.
Таблица на месте, всё, что было после рокового момента, откатано. Этот фокус логический дамп не умеет в принципе: в нём нет ни ночного WAL, ни механизма остановки на произвольной секунде. PITR восстанавливает не «состояние из файла», а «состояние на момент», которого никто специально не сохранял.
42.4.1 Подводный камень: archive_mode требует рестарта
Самая обидная засада в PITR. archive_mode - параметр уровня
сервера, он применяется только при рестарте. Включить его на лету
нельзя - в отличие от archive_command, который перечитывается по
reload.
Из этого следует жёсткое правило: архив включают заранее, в
спокойное время, а не в тот момент, когда копия уже понадобилась. Если
archive_mode был off, то WAL за прошедшее время уже не
архивировался - и восстанавливать PITR не из чего, как бы быстро ты
сейчас ни включил архив.
-- архив включён и применился, или ещё ждёт рестарта?
SELECT name, setting, pending_restart
FROM pg_settings WHERE name IN ('archive_mode', 'archive_command');pending_restart = true на archive_mode означает «я поменял
настройку, но она вступит в силу только после рестарта» - до него
архив не работает.
42.5 Базовая копия - это запускаемый кластер
Полезная ментальная модель: то, что снимает pg_basebackup, - не
«архив для распаковки», а готовый кластер. Это побайтовая копия
PGDATA, которую можно просто запустить вторым сервером, и она поднимется
с теми же данными на момент копии.
Отсюда видно родство с физической репликацией из прошлой части: standby начинается ровно с такой базовой копии, к которой потом доливается поток WAL. PITR - это та же копия плюс архив, но с явной точкой остановки вместо бесконечного догоняющего потока.
Поэтому проверка бэкапа проста и обязательна: разверни базовую копию отдельным сервером и убедись, что он стартует и данные на месте. Бэкап, который ни разу так не проверяли, в день аварии может оказаться нерабочим - и это выяснится в худший момент. Какие именно файлы копируются и как устроен replay - это форки и журнал из предыдущих частей; справка - backup-pitr.
Уроки в sandbox
lab-42.1. Архив WAL и привязка момента к сегменту
Полное восстановление на точку требует отдельной топологии с перезапуском сервера. Здесь разберём то, что доступно на одном работающем сервере: проверим состояние архива, привяжем текущий момент к сегменту WAL и увидим, почему archive_mode требует рестарта. Сначала предскажешь, потом проверишь.
Посмотри состояние архива:
SELECT name, setting, pending_restart FROM pg_settings WHERE name IN ('archive_mode','wal_level');. Запомни значения.Узнай текущую позицию журнала и её сегмент:
SELECT pg_current_wal_lsn(), pg_walfile_name(pg_current_wal_lsn());- имя файла и есть тот сегмент, который ушёл бы в архив.Предскажи: применится ли archive_mode сразу, если его включить через ALTER SYSTEM? Затем:
ALTER SYSTEM SET archive_mode = on;иSELECT pg_reload_conf();.Проверь:
SELECT name, setting, pending_restart FROM pg_settings WHERE name = 'archive_mode';- setting может показать on, но pending_restart = true: настройка ждёт рестарта, до него архив не работает.Верни как было:
ALTER SYSTEM RESET archive_mode;иSELECT pg_reload_conf();.
sandbox с автопроверкой - открыть в песочнице
Резюме
- Планируй восстановление, а не бэкап: вопрос не «есть ли копия», а «что и за сколько мы сможем восстановить» - под это и выбирают инструмент.
- pg_dump - логический снимок на момент старта, переносим между версиями, но медленно восстанавливается и не умеет «докрутить до позже».
- PITR собирается из базовой копии (pg_basebackup) плюс непрерывного архива WAL (archive_mode + archive_command).
- PITR восстанавливает на любую точку между копией и «сейчас» - это тот же replay, что в crash recovery, но с явной целью (recovery_target_time/LSN).
- Классический сценарий - откат на момент перед ошибочным DROP, чего логический дамп не умеет в принципе.
- archive_mode применяется только при рестарте; архив включают заранее, иначе восстанавливать PITR не из чего.
- Базовая копия - это запускаемый кластер; бэкап обязательно проверяют разворачиванием, иначе он может оказаться нерабочим в день аварии.
Контрольные вопросы
Почему говорят «планируй восстановление, а не бэкап»?
Показать ответ
Потому что ценность не в факте копии, а в способности восстановиться: на нужный момент и за приемлемое время. Эта формулировка задаёт выбор инструмента. «Вернуть вчерашнюю базу» - хватит pg_dump. «Вернуть состояние за минуту до аварии» - нужен PITR. «Потерять не больше N секунд при падении primary» - это уже синхронная репликация. Бэкап без проверенного восстановления - надежда, а не страховка.
Чем PITR умеет то, чего не может pg_dump?
Показать ответ
pg_dump хранит согласованный снимок ровно на момент своего старта - ни раньше, ни позже, и «докрутить» его нельзя. PITR держит базовую копию плюс непрерывный архив WAL, поэтому может восстановить состояние на любой момент между копией и «сейчас», задав цель recovery_target_time или LSN. Это позволяет, например, остановиться за секунду до ошибочного DROP - чего в дампе сделать нечем, в нём просто нет ни того WAL, ни механизма остановки.
Почему archive_mode нельзя включить в момент, когда копия уже понадобилась?
Показать ответ
archive_mode - параметр уровня сервера и применяется только при рестарте, а не по reload. Но дело даже не в рестарте: пока архив был выключен, WAL за прошедшее время не сохранялся. PITR строится из архива WAL после базовой копии; если архива за нужный период нет, восстанавливать не из чего, как быстро ты архив сейчас ни включай. Поэтому его включают заранее, в спокойное время.
Почему базовую копию называют «запускаемым кластером» и зачем это знать?
Показать ответ
pg_basebackup снимает побайтовую копию PGDATA - это не архив для распаковки, а готовый каталог данных, который можно просто запустить вторым сервером, и он поднимется с данными на момент копии. Знать это важно по двум причинам: понятно родство с физической репликацией (standby стартует с такой же копии плюс поток WAL), и понятно, как проверять бэкап - развернуть копию отдельным сервером и убедиться, что он стартует и данные на месте.
Как родственны crash recovery и PITR?
Показать ответ
Оба восстанавливают состояние, проигрывая WAL поверх базы. Crash recovery берёт последнюю контрольную точку и катит WAL до самого конца журнала (до последней записи). PITR берёт базовую копию и катит архивный WAL до явно заданной цели - времени, LSN или именованной точки - и там останавливается. Механизм replay тот же; разница только в том, до какого места проигрывать и откуда брать журнал (свой текущий против архива).