Резервное копирование
Архив журналов предзаписи
13
Авторские права
© Postgres Professional, 2018–2022
Авторы: Егор Рогов, Павел Лузанов, Илья Баштанов
Использование материалов курса
Некоммерческое использование материалов курса (презентации,
демонстрации) разрешается без ограничений. Коммерческое
использование возможно только с письменного разрешения компании
Postgres Professional. Запрещается внесение изменений в материалы
курса.
Обратная связь
Отзывы, замечания и предложения направляйте по адресу:
Отказ от ответственности
Компания Postgres Professional не несет никакой ответственности за
любые повреждения и убытки, включая потерю дохода, нанесенные
прямым или непрямым, специальным или случайным использованием
материалов курса. Компания Postgres Professional не предоставляет
каких-либо гарантий на материалы курса. Материалы курса
предоставляются на основе принципа «как есть» и компания Postgres
Professional не обязана предоставлять сопровождение, поддержку,
обновления, расширения и изменения.
2
Темы
Файловый архив — непрерывная архивация
Потоковый архив — утилита pg_receivewal
Восстановление с использованием архива
Очистка архива
3
Непрерывная архивация
сервер
файлы WAL
select, insert
update, delete
archiver
archive_command
вызывается
для заполненного сегмента,
должна завершиться
со статусом 0
архив WAL
+ вся настройка внутри СУБД
− записи попадают в архив с задержкой
archive_mode = on
archive_command
archive_timeout
Раз у нас есть базовая резервная копия и журнал предзаписи, то,
добавляя каким-то образом к копии все новые журнальные файлы,
генерируемые сервером, мы можем восстановить систему не только на
момент копирования файловой системы, но и вообще на произвольный
момент времени.
И такая возможность есть. Но журнальные записи добавляются не
к самой резервной копии, а в отдельный «архив».
Отправка журнальных файлов в архив реализуется фоновым
процессом archiver, который включается параметром archive_mode = on.
Для копирования определяется произвольная команда shell
в параметре archive_command. Она вызывается при заполнении
очередного сегмента WAL. Если команда завершается с нулевым
статусом, то считается, что сегмент успешно помещен в архив и может
быть удален с сервера. При ненулевом статусе этот сегмент
(и следующие за ним) не будут удаляться, а сервер будет периодически
повторять команду архивирования, пока не получит 0.
Параметр archive_timeout позволяет указать максимальное время
переключения на новый сегмент WAL — это позволяет при невысокой
активности сервера сохранять тем не менее журналы не реже, чем
хотелось бы (иными словами, потерять данные максимум за указанное
время). Переключение на новый сегмент можно выполнить и вручную
с помощью функции pg_switch_wal().
4
archive_command
Команда ОС, архивирующая заполненный сегмент WAL
копирует файл %p в архив под именем %f,
сам архив может быть организован любым образом
должна завершаться со статусом 0 только при успехе
(пустая команда не считается успешной и приостанавливает архивацию)
не должна перезаписывать уже существующие файлы
должна гарантировать запись в энергонезависимую память
удобно реализовать нужную логику в собственном скрипте
Мониторинг
текущий статус — представление pg_stat_archiver
удобно включить коллектор сообщений (logging_collector = on)
и получать диагностику в журнале сообщений сервера
Команда архивирования должна скопировать указанный файл в некий
архив. Архив может быть организован любым образом. Например, это
может быть файловая система на отдельном сервере.
Команда обязана завершаться с нулевым статусом только в случае
успеха.
Команда не должна перезаписывать уже существующие файлы, так как
это скорее всего означает какую-то ошибку, и перезапись файла может
погубить архив.
Для гарантии надежности команда должна обеспечить попадание
файла в энергонезависимую память: иначе при сбое архива можно
потерять сегмент, если сервер PostgreSQL успеет его удалить.
Текущий статус архивации показывает представление pg_stat_archiver.
Удобно включить сбор сообщений с помощью процесса
logging_collector, так как в этом случае сообщения об ошибках при
выполнения ar chive_command будут попадать в журнал сервера.
Если подразумевается сложная логика, то ее удобно записать в скрипт
и использовать имя скрипта в качестве команды копирования.
6
pg_receivewal
сервер
файлы WAL
select, insert
update, delete
wal sender
pg_receivewal
архив WAL
слот
.partial
max_wal_senders
max_replication_slots
+ записи попадают в архив сразу
− требуется отдельная утилита
при подключении читает WAL
с начала сегмента, следующего
за последним заполненным
сегментом в каталоге
если каталог пустой, начинает
с текущего сегмента сервера
Можно организовать пополнение архива иным способом, с помощью
протокола репликации. Для этого используется утилита pg_receivewal.
Обычно утилита запускается на отдельном сервере и подключается
к серверу с параметрами, указанными в ключах. Утилита может
(и должна) использовать слот репликации, чтобы гарантированно не
потерять записи.
Утилита формирует файлы аналогично тому, как это делает сам
сервер, и записывает их в указанный каталог. Еще не до конца
заполненные сегменты отличаются префиксом .partial. Синхронизация
с файловой системой по умолчанию происходит только при закрытии
файла-сегмента.
Архивирование всегда начинается с начала сегмента, следующего за
последним уже полностью заполненным сегментом, который
присутствует в архиве. Если архив пуст (первый запуск), архивирование
начинается с начала текущего сегмента. Вместе со слотом это
гарантирует отсутствие пропусков в архиве, даже если утилита
отключалась на некоторое время. Утилита будет получать записи
бесконечно, но, если указан ключ --endpos=lsn, она завершит работу
по получении записи с заданным LSN.
Требуется учесть, что сама по себе утилита не запускается
автоматически (как сервис) и не демонизируется. Она потребует
дополнительного мониторинга и (в случае репликации) действий по
переключению на другой сервер.
8
Базовая копия
сервер
файлы WAL
select, insert
update, delete
pg_basebackup
wal sender
базовая копия
поток
данных
архив WAL
журнальные
записи в базовой копии
теперь не нужны
Если мы располагаем настроенным архивом журнала предзаписи,
то в базовой резервной копии файлы журнала становятся не
обязательны — ведь их при восстановлении можно получить из архива.
Поэтому pg_basebackup можно запускать с ключом --wal-method=none.
(Но и никакого вреда от журнальных файлов, кроме занимаемого
объема, внутри базовой копии тоже нет. Более того, они позволят
восстановить систему в ситуации, если архив окажется недоступен.)
10
tablespace_map
пути для табличных пространств
backup_label
начальная позиция и др.
recovery.signal
создается вручную
postgresql.conf
restore_command
целевая точка
и др.
Восстановление
сервер
архив WAL
начальная
позиция
целевая точка
восстановления
restore_command
startup
Процессом восстановления управляют три файла и параметры.
Файл tablespace_map генерируется при создании базовой резервной
копии и содержит пути для табличных пространств. Если
символические ссылки в pg_tblspc отсутствуют (это верно для формата
tar), то они будут созданы при старте сервера на основании
информации в tablespace_map.
С этим файлом мы уже встречались в теме «Базовая резервная копия».
Файл метки backup_label также генерируется автоматически при
создании базовой резервной копии и содержит название, время
создания копии и — самое важное — номер линии времени, название
сегмента WAL и позицию в нем, с которой надо начинать
восстановление.
Третий файл, recovery.signal, создается вручную. Его наличие дает
указание серверу перейти в режим восстановления. Содержимое
файла игнорируется. Если recovery.signal отсутствует, то PostgreSQL
считает, что он выполняет автоматическое восстановление после сбоя.
Если же файл есть, сервер понимает, что происходит управляемое
пользователем восстановление из резервной копии.
В версиях PostgreSQL до 11 параметры восстановления задавались
в отдельном конфигурационном файле recovery.conf. Начиная с версии
12, параметры восстановления задаются так же, как и все остальные.
11
По умолчанию проигрываются все доступные журнальные
записи
Восстановление до определенной точки (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_t arget_*), базы данных будут восстановлены максимально
близко к моменту сбоя. Однако процесс восстановления можно
остановить и в любой другой момент, указав целевую точку.
Параметр recovery_target = 'immediate' остановит восстановление, как
только будет достигнута согласованность. Фактически, это
эквивалентно восстановлению из базовой копии без архива.
Параметр recovery_target_name позволяет указать именованную точку
восстановления, созданную ранее с помощью функции
pg_create_restore_point(). Это полезно, если заранее известно, что
может потребоваться восстановление.
Параметр recovery_target_time позволяет указать произвольное время
(timestamp), recovery_target_xidпроизвольную транзакцию,
recovery_t arget_lsnномер LSN. С помощью параметра
recovery_t arget_inclusive можно включить или исключить саму точку.
12
Команда восстановления
restore_command — команда, «обратная» archive_command:
копирует файл %f из архива в %p
должна завершаться со статусом 0 только при успехе
По окончании восстановления (если задана цель)
recovery_target_action =
pause
promote
shutdown
Настройки восстановления
завершить — pg_wal_replay_resume()
задать новую цель + рестарт
останавливается
принимает подключения
Для восстановления необходимо задать параметр restore_command,
который определяет команду, «обратную» команде архивирования
archive_command. Она должна скопировать файл из архива в каталог
pg_wal и завершаться со статусом 0 только при успехе. Это очень
важно, так как в процессе восстановления сервер может выполнять
команду для файлов, которых не окажется в архиве — это не ошибка,
но команда должна завершиться с ненулевым статусом.
Если задана цель, параметр recover y_target_action позволяет выбрать
состояние, в котором окажется сервер по окончании восстановления.
По умолчанию (значение pause) процедура восстановления
приостанавливается. Администратор может выполнить запросы
к данным и решить, корректно ли была выбрана цель, после чего либо
завершить восстановление, вызвав функцию pg_wal_replay_resume(),
либо задать новую цель, перезапустить сервер и продолжить
применение журнальных записей.
Если задано значение promote, сервер сразу сможет принимать
запросы на подключения.
Значение shutdown приведет к остановке сервера. При этом файл
recovery.signal не удаляется.
13
Окончание восстановления
recovery.signal recovery.signal
backup_label backup_label.old
возможные проблемы диагностируются
по журналу сообщений сервера
сервер
архив WAL
файлы WAL
select, insert
update, delete
перенастроить
на другой архив?
когда пора
удалять сегмент
из архива?
После того, как восстановление закончено, процесс startup
завершается, postmaster запускает остальные служебные процессы,
необходимые для работы экземпляра, и сервер начинает работать
в обычном режиме. Файл recovery.signal удаляется, backup_label
переименовывается в backup_label.old.
Возможна ситуация, когда запущенный сервер не стартует. В этом
случае в операционной системе будут отсутствовать процессы (и не
будет файла postmaster.pid), а recovery.signal не будет удален. Причину
ошибки можно узнать из журнала сообщений сервера (например, в
параметрах была допущена ошибка). После исправления причины
ошибки сервер следует запустить еще раз.
Важный момент: если на сервере-источнике было настроено
непрерывное архивирование, то на резервном сервере его надо либо
отключить, либо перенаправить в другой архив.
15
Порядковый номер, +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_t arget_timeline = 'latest' (по умолчанию с версии 12), то, дойдя
то точки ветвления, применение записей WAL продолжится по второй
(более поздней) линии.
Если же указать параметр recovery_target_timeline = '1', то
восстановление продолжится по первой (указанной) линии, а если
указать recovery_target_timeline = 'current', то по текущей (в нашем
случае тоже по линии 1, это поведение по умолчанию до версии 11).
Информацию о точках ветвления PostgreSQL берет из файлов истории
pg_wal/N.history. Поэтому их никогда не следует удалять из архива.
17
Очистка архива
сервер
файлы WAL
select, insert
update, delete
pg_basebackup
wal sender
базовая копия
архив WAL
контрольная
точка
можно удалить
(pg_archivecleanup)
Архив со временем разрастается, поэтому требуется периодическая
очистка от ненужных файлов.
Для очистки можно воспользоваться утилитой pg_archivecleanup.
Утилите нужно указать имя сегмента WAL, и она удалит все ему
предшествующие.
Вопрос в том, как определить позицию в архиве, начиная с которой
сегменты уже не нужны.
Если архив используется только для восстановления одного резервного
экземпляра, можно выполнять очистку сразу после восстановления.
Для этого служит параметр recover y_end_command, в котором задается
команда (например, pg_archivecleanup), которая выполнится по
окончании восстановления. В команде можно использовать
комбинацию %r, которая заменится на имя файла, содержащего запись
о последней выполненной контрольной точке.
Но если архив должен поддерживать восстановление из нескольких
базовых резервных копий, то для автоматизации очистки либо придется
написать собственный скрипт, либо — что лучше — воспользоваться
одной из сторонних программ резервного копирования, таких как
pg_probackup, которые позволяют гибко настроить политику хранения
резервных копий.
19
Итоги
Физическое резервирование —
базовые резервные копии и архив журнала предзаписи
Хорошо подходит
для текущего периодического резервирования
для восстановления после сбоя с минимальной потерей данных
для восстановления на произвольный момент времени
для резервирования данных большого объема
Плохо подходит
для длительного хранения
Не подходит
для миграции на другую платформу
20
Практика
1. На первом сервере создайте базу данных и в ней таблицу
с какими-нибудь данными.
2. Настройте непрерывное архивирование.
3. Сделайте базовую резервную копию кластера с помощью
pg_basebackup, без файлов журнала.
4. Вставьте еще несколько строк в таблицу и убедитесь,
что текущий сегмент WAL попал в архив.
5. Восстановите второй сервер из резервной копии, указав
в параметрах одну только команду восстановления.
Проверьте, что в таблице восстановились все строки.
6. Остановите второй сервер и восстановите его повторно
из той же резервной копии, на этот раз указав целевую точку
восстановления immediate. Проверьте таблицу.