Резервное копирование
Архив журналов предзаписи
16
Авторские права
© Postgres Professional, 2017–2025
Авторы: Егор Рогов, Павел Лузанов, Илья Баштанов, Алексей Береснев
Фото: Олег Бартунов (монастырь Пху и пик Бхрикути, Непал)
Использование материалов курса
Некоммерческое использование материалов курса (презентации,
демонстрации) разрешается без ограничений. Коммерческое
использование возможно только с письменного разрешения компании
Postgres Professional. Запрещается внесение изменений в материалы
курса.
Обратная связь
Отзывы, замечания и предложения направляйте по адресу:
edu@postgrespro.ru
Отказ от ответственности
Компания Postgres Professional не несет никакой ответственности за
любые повреждения и убытки, включая потерю дохода, нанесенные
прямым или непрямым, специальным или случайным использованием
материалов курса. Компания Postgres Professional не предоставляет
каких-либо гарантий на материалы курса. Материалы курса
предоставляются на основе принципа «как есть» и компания Postgres
Professional не обязана предоставлять сопровождение, поддержку,
обновления, расширения и изменения.
2
Темы
Файловый архив — непрерывная архивация
Потоковый архив — утилита pg_receivewal
Восстановление с использованием архива
Очистка архива
3
Непрерывная архивация
сервер
файлы WAL
select, insert
update, delete
archiver
archive_command или archive_library
копируется
отработанный
сегмент
архив WAL
+ вся настройка внутри СУБД
− записи попадают в архив с задержкой
archive_mode = on
archive_command
archive_library
archive_timeout
Базовая резервная копия, рассмотренная в предыдущей теме,
содержит все журнальные записи, необходимые для согласования
страниц файлов данных. Такая копия называется автономной и
позволяет восстановить состояние сервера на момент окончания
резервирования.
Если же к автономной копии добавлять новые файлы журнала
предзаписи, генерируемые сервером, можно будет восстановить
кластер на произвольный момент времени. На практике заполненные
журнальные сегменты копируются не в саму копию, а в отдельный
архив. Этим занимается процесс archiver при значении параметра
archive_mode = on.
В PostgreSQL есть два способа копирования сегмента WAL в архив:
1. Командой ОС. При переключении на очередной сегмент WAL
процесс выполняет команду, которую он получает из параметра
archive_command.
2. С помощью функций модуля архивирования (начиная с версии 15).
Имя модуля задается параметром archive_library.
На слабо загруженных серверах параметром archive_timeout задают
максимальное время, которое может пройти до переключения на новый
сегмент WAL. Переключение можно выполнить и вручную, используя
функцию pg_switch_wal.
4
archive_command
Команда ОС, архивирующая заполненный сегмент WAL
копирует файл %p в архив под именем %f,
сам архив может быть организован любым образом
должна завершаться со статусом 0 только при успехе
не должна перезаписывать уже существующие файлы
должна гарантировать запись в энергонезависимую память
удобно реализовать нужную логику в собственном скрипте
Мониторинг
текущий статус — представление pg_stat_archiver
удобно включить коллектор сообщений (logging_collector = on)
и получать диагностику в журнале сообщений сервера
Команда архивирования должна скопировать указанный файл в некий
архив. Архив может быть организован любым образом. Например, это
может быть файловая система на отдельном сервере.
Команда обязана завершаться с нулевым статусом только при успехе;
в этом случае скопированный сегмент может быть удален контрольной
точкой. При ненулевом статусе не скопированный сегмент и следующие
за ним не удаляются, а сервер периодически повторяет команду
архивирования, пока не получит 0.
Команда не должна перезаписывать уже существующие файлы, так как
это скорее всего означает какую-то ошибку, и перезапись файла может
погубить архив.
Для гарантии надежности команда должна обеспечить попадание
файла в энергонезависимую память: иначе при сбое архива можно
потерять сегмент, если сервер PostgreSQL успеет его удалить.
Текущий статус архивации показывает представление pg_stat_archiver.
Удобно включить сбор сообщений с помощью процесса
logging_collector, так как в этом случае сообщения об ошибках при
выполнения archive_command будут попадать в журнал сервера.
Если подразумевается сложная логика, то ее удобно записать в скрипт
и использовать имя скрипта в качестве команды копирования.
6
pg_receivewal
сервер
файлы WAL
select, insert
update, delete
wal sender
pg_receivewal
архив WAL
слот
.partial
max_wal_senders
max_replication_slots
+ записи попадают в архив сразу
− требуется отдельная утилита
− нужен слот репликации
Можно организовать пополнение архива иным способом, с помощью
протокола репликации. Для этого используется утилита pg_receivewal.
Обычно утилита запускается на отдельном сервере, хранящем архив.
Она формирует файлы аналогично тому, как это делает сам сервер,
и записывает их в указанный каталог. Не до конца заполненные
сегменты имеют суффикс .partial. По умолчанию синхронизация кеша
с файловой системой происходит только при закрытии сегмента WAL,
но можно сделать запись синхронной, задав параметр --synchronous.
Утилита может сжимать сегменты WAL. Для этого в параметре
--compress нужно указать алгоритм (gzip или lz4) и уровень сжатия.
При первом запуске (когда архив пуст) архивирование начнется
с начала текущего сегмента. Обычно же архивирование начинается
с начала сегмента, следующего за последним заполненным сегментом
в архиве. При использовании слота репликации это гарантирует
отсутствие пропусков в архиве, даже если утилита отключалась на
некоторое время.
По умолчанию утилита получает записи бесконечно, но можно
завершить ее работу при получении записи с заданным LSN, если
указать --endpos=lsn.
Учтите, что утилита не запускается автоматически как сервис и не
демонизируется.
8
Базовая копия
сервер
файлы WAL
select, insert
update, delete
pg_basebackup
wal sender
базовая копия
поток
данных
архив WAL
журнальные
записи в базовой копии
теперь не нужны
Если мы располагаем настроенным архивом журнала предзаписи,
то в базовой резервной копии файлы журнала перестают быть
обязательными — ведь их при восстановлении можно получить
из архива. Поэтому pg_basebackup можно запускать с ключом
--wal-method=none.
(Но и никакого вреда от журнальных файлов внутри базовой копии,
кроме занимаемого объема, тоже нет. Более того, они позволят
восстановить систему в ситуации, если архив окажется недоступен.)
10
recovery.signal
сигнализирует о восстановлении
из резервной копии
tablespace_map
пути для табличных пространств
backup_label
начальная позиция и др.
postgresql.conf
restore_command
целевая точка
и др.
Восстановление
сервер
архив WAL
начальная
позиция
целевая точка
восстановления
restore_command
startup
Процессом восстановления управляют три файла и параметры.
Файл recovery.signal создается вручную. Его наличие дает указание
серверу перейти в режим восстановления. Содержимое файла
игнорируется. Если recovery.signal отсутствует, то PostgreSQL считает,
что он выполняет автоматическое восстановление после сбоя. Если же
файл есть, сервер понимает, что происходит управляемое
пользователем восстановление из резервной копии и обращает
внимание на два других файла, которые генерируются при создании
базовой резервной копии:
●
Файл tablespace_map содержит пути для табличных пространств.
Если символические ссылки в pg_tblspc отсутствуют (это верно для
формата tar), то они будут созданы при старте сервера на основании
информации в tablespace_map.
С этим файлом мы уже встречались в теме «Базовая резервная
копия».
●
Файл метки backup_label содержит название, время создания копии
и — самое важное — название сегмента WAL и позицию в нем,
с которой надо начинать восстановление.
При восстановлении процесс startup читает файлы из архива
с помощью команды из параметра restore_command и применяет
журнальные записи от начальной позиции, указанной в файле метки,
до целевой точки восстановления.
12
Команда ОС, восстанавливающая сегмент WAL
выполняет действие, «обратное» archive_command
копирует файл %f из архива на сервер по пути %p
должна завершаться со статусом 0 только при успехе
(может вызываться для несуществующих файлов)
Мониторинг
log_startup_progress_interval = 10s
журналирование статуса процесса startup
restore_command
Параметр restore_command определяет команду, «обратную» команде
архивирования archive_command. Она должна скопировать файл из
архива в каталог pg_wal и завершаться со статусом 0 только при
успехе. Это очень важно, так как в процессе восстановления сервер
может выполнять команду восстановления для файлов, которых не
окажется в архиве — это не ошибка, но команда должна завершиться
с ненулевым статусом.
Начиная с 14-й версии PostgreSQL изменение параметра
restore_command не требует рестарта сервера.
С 15-й версии за состоянием процесса восстановления можно следить
в журнале сообщений сервера при включенном параметре
log_startup_progress_interval. При значении по умолчанию информация
сбрасывается в журнал раз в 10 секунд.
В более ранних версиях информация о текущем состоянии
восстановления отображалась только в имени unix-процесса startup.
13
Аналог контрольной точки при восстановлении
сброс грязных буферов
запись в управляющий файл
удаление ненужных сегментов WAL
Выполняется при применении записи о контрольной точке
если после точки перезапуска прошло не менее checkpoint_timeout
или объем WAL приближается к max_wal_size
Мониторинг
log_checkpoints
pg_stat_bgwriter
Точка перезапуска
Когда при восстановлении процесс startup применяет журнальные
записи, данные в общей памяти сервера изменяются так же, как при
обычной работе: появляются грязные буферы. Если произойдет сбой,
после него нужно будет повторять восстановление, и на этот случай
необходимо хранить журнальные записи. Чтобы ограничить объем
хранимых записей и не начинать восстановление с самого начала,
сервер периодически выполняет точки перезапуска (restart points),
сбрасывая, как при контрольной точке, грязные буферы структур общей
памяти: буферного кеша, кеша clog и других. При успешном
завершении точки перезапуска сервер делает запись в управляющем
файле и удаляет сегменты WAL, которые целиком предшествуют ее
началу.
Точка перезапуска выполняется, когда процесс startup встречает в WAL
запись о контрольной точке, если после последней точки перезапуска
прошло не менее checkpoint_timeout времени или если объем журнала
приближается к значению max_wal_size. Иными словами, точка
перезапуска инициируется журнальной записью о контрольной точке, но
если ни одно из условий не выполняется, запись пропускается.
Если включен параметр log_checkpoints, в журнал сообщений будет
попадать информация обо всех точках перезапуска, а представление
pg_stat_bgwriter показывает накопленную статистику.
14
Восстановление до определенной точки (PITR)
recovery_target = 'immediate' только восстановить согласованность
recovery_target_name = 'имя' до именованной точки, созданной
pg_create_restore_point('имя')
recovery_target_time = 'время' до указанного времени
recovery_target_xid = 'xid' до указанной транзакции
recovery_target_lsn = 'lsn' до указанного LSN
recovery_target_inclusive = on|off включать ли указанную точку
recovery_target_action = pause
pause
promote принимает подключения
shutdown останавливается
Цель восстановления
завершить — pg_wal_replay_resume()
задать новую цель + рестарт
Если цель восстановления не задана, кластер будет восстановлен
максимально близко к моменту сбоя. Однако процесс восстановления
можно остановить и в любой другой момент, указав целевую точку:
●
Параметр recovery_target = 'immediate' остановит восстановление,
как только будет достигнута согласованность. Фактически, это
эквивалентно восстановлению из базовой копии без архива.
●
Параметр recovery_target_name позволяет указать именованную
целевую точку восстановления, созданную заранее с помощью
функции pg_create_restore_point.
●
Параметр recovery_target_time позволяет указать произвольное
время (timestamp), recovery_target_xid — произвольную транзакцию,
recovery_target_lsn — номер LSN. С помощью параметра
recovery_target_inclusive можно включить или исключить саму точку.
Параметр recovery_target_action позволяет выбрать состояние,
в котором окажется сервер по достижении целевой точки:
●
При значении pause восстановление приостанавливается.
Администратор может выполнить запросы и решить, корректно ли
была выбрана цель, после чего либо завершить восстановление
(функция pg_wal_replay_resume), либо задать новую цель,
перезапустить сервер и продолжить применение записей WAL.
●
Если задано значение promote, сервер сразу сможет принимать
запросы на подключения.
●
Значение shutdown приведет к остановке сервера. При этом файл
recovery.signal не удаляется.
15
recovery.signal удаляется
backup_label backup_label.old
выполняется recovery_end_command
проблемы диагностируются
по журналу сообщений
Окончание восстановления
сервер
архив WAL
файлы WAL
select, insert
update, delete
перенастроить
на другой архив?
После того как восстановление закончено, процесс startup завершается,
postmaster запускает остальные служебные процессы, необходимые
для работы экземпляра, и сервер начинает работать
в обычном режиме. Файл recovery.signal удаляется, backup_label
переименовывается в backup_label.old.
В параметре recovery_end_command можно задать команду, которая
выполнится по окончании восстановления; это могут быть действия
с файловой системой, очистка архива, отправка уведомления и др.
Возможна ситуация, когда запущенный сервер не стартует. В этом
случае в операционной системе будут отсутствовать процессы
экземпляра (и не будет файла postmaster.pid), а recovery.signal не будет
удален. Причину ошибки можно узнать из журнала сообщений сервера
(например, в параметрах была допущена ошибка). После исправления
причины ошибки сервер следует запустить еще раз.
Важный момент: если на сервере-источнике было настроено
непрерывное архивирование, то на резервном сервере его надо либо
отключить, либо перенаправить в другой архив.
17
Порядковый номер, +1 при каждом восстановлении
номер N линии времени входит в имя сегмента WAL
история сохраняется в файле pg_wal/N.history и архивируется
Линии времени
1
2
целевая
точка
1
2
recovery_target_timeline = 'latest'
восстановление по последней линии
(по умолчанию)
recovery_target_timeline = 'current'
восстановление по текущей линии
recovery_target_timeline = '1'
восстановление по указанной линии
После восстановления на момент в прошлом сервер начинает
генерировать новые записи WAL, номера которых будут повторять
номера записей «из прошлой жизни». Чтобы не потерять записи и,
вместе с ними, возможность восстановления на другой момент,
PostgreSQL вводит понятие линии времени. После каждого
восстановления с использованием recovery.signal номер линии времени
увеличивается, и этот номер является частью номера сегментов WAL.
Линии времени образуют древовидную структуру, на рисунках приведен
пример. Первая линия имеет номер 1. Произошло восстановление на
момент времени в прошлом, и началась линия 2.
Если выполнить восстановление с указанием параметра
recovery_target_timeline = 'latest' (по умолчанию), то, дойдя то точки
ветвления, применение записей WAL продолжится по второй (более
поздней) линии.
Если же указать параметр recovery_target_timeline = '1', то
восстановление продолжится по первой (указанной) линии, а если
указать recovery_target_timeline = 'current', то по текущей (в нашем
случае тоже по линии 1).
Информацию о точках ветвления PostgreSQL берет из файлов истории
pg_wal/N.history. Поэтому их никогда не следует удалять из архива.
19
Очистка архива
сервер
файлы WAL
select, insert
update, delete
pg_basebackup
wal sender
базовая копия
архив WAL
контрольная
точка
pg_archivecleanup
Архив со временем разрастается, поэтому требуется периодическая
очистка от ненужных файлов.
Для очистки можно воспользоваться утилитой pg_archivecleanup.
Утилите нужно указать имя сегмента WAL, и она удалит все ему
предшествующие.
Вопрос в том, как определить позицию в архиве, начиная с которой
сегменты уже не нужны.
Если архив используется только для восстановления из одной базовой
резервной копии, можно выполнять очистку сразу после ее обновления.
Но если архив должен поддерживать восстановление из нескольких
базовых резервных копий, то для автоматизации очистки либо придется
написать собственный скрипт, либо — что лучше — воспользоваться
одной из сторонних программ резервного копирования, таких как
pg_probackup, которые позволяют гибко настроить политику хранения
резервных копий.
21
Итоги
Физическое резервирование —
базовые резервные копии и архив журнала предзаписи
Хорошо подходит
для текущего периодического резервирования
для восстановления после сбоя с минимальной потерей данных
для восстановления на произвольный момент времени
для резервирования данных большого объема
Плохо подходит
для длительного хранения
Не подходит
для миграции на другую платформу
22
Практика
1. На сервере alpha создайте базу данных и таблицу с данными.
2. Настройте непрерывное архивирование.
3. Сделайте копию кластера без файлов журнала.
4. Вставьте еще несколько строк в таблицу и убедитесь,
что текущий сегмент WAL попал в архив.
5. Восстановите сервер beta из резервной копии, указав
в параметрах одну только команду восстановления.
6. Снова восстановите сервер beta из той же резервной копии,
на этот раз указав целевую точку восстановления immediate.
После выполнения практических заданий удалите базы данных
и сбросьте изменения параметров конфигурации.
23
Практика+
1. На сервере alpha создайте таблицу, в которую будут
периодически записываться данные. Создайте физическую
резервную копию и настройте непрерывную архивацию
WAL.
2. Вставьте в подготовленную таблицу трижды по 100 строк
(данные за январь, февраль и март), отмечая время сразу
после вставки. Между вставками удалите некоторые строки:
сымитируйте ситуацию, в которой пользователь случайно
удаляет часть данных в неизвестный момент, но проблему
замечают не сразу.
3. Восстановите удаленные данные, не останавливая при этом
сервер alpha.
3. Используйте сервер beta как вспомогательный.