Непрерывное архивирование и восстановление на момент времени (Point-in-Time Recovery (PITR))

24.3. Непрерывное архивирование и восстановление на момент времени (Point-in-Time Recovery (PITR))

В каждый момент времени, PostgreSQL обслуживает журнал опережающей записи (WAL), который расположен в подкаталоге pg_xlog/ каталога с данными кластера баз данных. Записи журнала меняются каждый раз, когда в файлы баз данных вносятся изменения. Первично, журнал существует для целей безопасного восстановления после краха сервера: если происходит крах, то СУБД может восстановить свою целостность с помощью "воспроизведения" записей, сделанных после последней контрольной точки. Однако, наличие журнала, делает возможным использование третьей стратегии резервного копирования баз данных: можно комбинировать резервное копирование на уровне файловой системы с резервным копированием файлов WAL. Если требуется восстановление, то для приведения системы в текущее состояние делается восстановление из резервной копии файловой системы и затем воспроизведение из резервной копии WAL файлов. Такой подход более сложен для администрирования, чем один из описанных выше, но он имеет некоторые значительные преимущества:

  • Нет необходимости вначале делать полностью целостную резервную копию файловой системы. Любая внутренняя нецелостность в резервной копии будет откорректирована при воспроизведении журнала (это не сильно отличается от того, что происходит при восстановлении после краха). Таким образом, нет необходимости делать снимок файловой системы, можно использовать только tar или похожие инструменты архивации.

  • Поскольку для воспроизведения можно комбинировать WAL файлы за неопределённо долгое время, непрерывное резервное копировании может выполняться просто с помощью непрерывной архивации WAL файлов. Это особенно важно для больших баз данных, где может быть неудобно делать полные резервные копии часто.

  • Нет необходимости воспроизвести записи WAL за всё время до конца. Можно остановить воспроизведение в любой точке и получить целостный снимок базы данных, на это время. Таким образом, данная технология поддерживает восстановление на момент времени: можно восстановить базу данных к её состоянию на любое время с момента выполнения резервной копии.

  • Если непрерывно передавать серии WAL файлов на другую машину, которая будет загружена из того же файла резервной копии базы данных, получается система горячего резерва: в любой момент мы можем запустить вторую машину и она будет иметь практически текущую копию базы данных.

Note: pg_dump и pg_dumpall не выполняют резервных копий файловой системы и не могут быть использованы как часть решения по непрерывной архивации. Такие дампы являются логическими и не содержат нужной информации, которая может быть использована для воспроизведения WAL.

Как и в обычной технологии резервного копирования файловой системы, данный метод поддерживает только восстановление всего кластера баз данных, но не его части. Также, требуется большое устройство хранения архивов: базовая резервная копия может быть громоздкой и нагруженные системы будут генерировать многомегабайтный WAL траффик, который необходимо архивировать. Тем не менее, этот способ резервного копирования является предпочтительным во многих ситуациях, когда необходима высокая надёжность.

Для успешного восстановления с помощью непрерывного архивирования (также называемого многими производителями СУБД "онлайновым резервным копированием"), вам необходима непрерывная последовательность архивированных WAL файл, с момента начала данного резервного копирования. Так что, для начала, вы должны настроить и протестировать процедуру архивирования WAL файлов перед тем как вы получите вашу первую базовую резервную копию. Соответственно, сперва будет рассказана механика архивирования WAL файлов.

24.3.1. Настройка архивирования WAL

В абстрактном понимании, запущенная СУБД PostgreSQL, производит последовательность WAL записей неопределённо долгое время. СУБД физически делит эту последовательность на файлы-сегменты WAL, которые обычно имеют размер в 16MB (хотя размер сегмента может быть изменён, при компиляции PostgreSQL). Файлы-сегменты получают цифровые имена, которые отражают их позцию в абстрактной последовательности WAL. Когда WAL архивирование не используется, система обычно создаёт только несколько файлов-сегментов и затем "зацикливает" их, переименовывая больше не нужные файлы-сегменты на более высокие номера сегментов. Предполагается, что файлы-сегменты, чьё содержимое предшествует последней контрольной точке, больше не представляют интереса и могут быть пущены в цикл.

При архивировании данных WAL, необходимо захватывать содержимое каждого файла-сегмента как только он заполняется и куда-то сохранять эти данные перед тем как файл-сегмент пускается в цикл для повторного использования. В зависимости от приложения и доступного аппаратного обеспечения, есть множество разных способов "куда-то сохранить данные": можно скопировать файлы-сегменты в смонтированный по NFS каталог на другую машину, записать их на ленточное устройство (убедившись, что у вас есть способ идентифицировать оригинальное имя каждого файла) или собрать их вместе и записать на болванку CD или что-либо другое. Чтобы предоставить администратору баз данных гибкость в этом плане, PostgreSQL не пытается делать какие-либо предположения о том как будет выполняться архивация. Вместо этого, PostgreSQL позволяет администратору указать команду shell, которая будет запущена для копирования завершённого файла-сегмента туда, куда нужно. Эта команда может быть столь же простой как cp или может вызывать сложный shell-скрипт — это решать вам.

Чтобы включить WAL архивирование, установите конфигурационный параметр wal_level в archive (или hot_standby), archive_mode в on и укажите shell-команду, которую вы будете использовать в конфигурационном параметре archive_command. На практике, эти настройки всегда будут размещаться в файле postgresql.conf. В archive_command, %p замещается полным путём к файлу для выполнения архивирования, а %f замещается только именем файла. (Полное имя получается относительно текущего рабочего каталога, т.е. каталога с кластером баз данных). Если в команде вам необходимо указать сам символ %, используйте %%. Простейшая команда, которой можно воспользоваться, может выглядеть так:

archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'  # Unix
archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"'  # Windows

и будет копировать архивируемые WAL сегменты в каталог /mnt/server/archivedir. (Команда дана как пример, а не как рекомендация и может не работать на всех платформах.) После того, как будет осуществлена замена параметров %p и %f, запускаемая команда может выглядеть так:

test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_xlog/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065

Похожая команда будет генерироваться для каждого нового архивируемого файла.

Команда архивирования будет запущена с правами того пользователя, из под которого запущен сервер PostgreSQL. Поскольку серии WAL файлов, которые будут архивироваться, содержат фактически всё, что есть в вашей базе данных, вы должны убедиться, что архивируемые данные защищены от посторонних глаз; например, производите архивацию в каталог, к которому нет прав доступа на чтение у группы и остальных пользователей.

Важно, что команда архивирования возвращает нулевой код, если и только если она завершилась успешно. При получении нулевого результата, PostgreSQL будет полагать, что файл успешно архивирован и удалит его или запустит в цикл. Однако, ненулевой код состояния скажет PostgreSQL, что файл не был архивирован; попытки архивировать его будут периодически предприниматься снова, пока не будет достигнут успешный результат.

Команда архивирования обычно разрабатывается так, чтобы не допускать перезаписи любых существующих архивных файлов. Такое поведение является важным для защиты целостности вашего архива в случае ошибок администратора (таки как перенаправление вывода двух разных серверов в один и тот же каталог архивирования).

Желательно протестировать вашу команду архивирования, чтобы убедиться, что она действительно не перезаписывает существующие файлы, и что она возвращает ненулевое состояние в этом случае. Команда для Unix, данная выше в качестве примера, делает это с помощью отдельного шага test. На некоторых Unix платформах, cp имеет такой ключ как -i, который может использоваться для этой же цели менее явно, но вы не должны полагаться на это без проверки правильного состояния при завершении команды. (В частности, GNU cp возвратит нулевой код состояния, если использован ключ -i и файл назначения существует, а это не то поведение, что нужно.)

При разработке процедуры архивирования, рассмотрите что произойдёт, если команда архивирования будет завершаться неудачей повторно, потому что некоторые аспекты требуют вмешательства оператора, если для архивирования не хватает места. Например, это может произойти, если вы записываете архивы на ленточное устройство без механизма автозамены; когда лента заполняется полностью, ничего архивироваться не будет пока вы не замените кассету. Вы должны убедиться, что любые ошибочные ситуации или обращения к оператору-человеку, соответственно обрабатываются так, чтобы решаться в разумно быстрые сроки. Пока ситуация не разрешиться, каталог pg_xlog/ продолжит наполняться файлами-сегментами WAL. (Если файловая система, на которой находится каталог pg_xlog/ заполнится до конца, PostgreSQL аварийно завершит свою работу. Подтверждённые транзакции потеряны не будут, но база данных будет оставаться недоступной пока вы не освободите место.)

Неважно с какой скоростью работает команда архивирования, пока она успевает архивировать WAL данные, которые генерируются сервером. Обычно работа продолжается даже если процесс архивирования немного отстаёт из-за ошибок. Если ошибки архивирования приводят к значительному опозданию, то это увеличивает объём данных, который может быть потерян в случае катастрофы. Это будет также означать, что каталог pg_xlog/ будет содержать большое количество ещё неархивированных файлов-сегментов, которые могут исчерпать доступное дисковое пространство. Вы должны мониторить процесс архивации, чтобы убедиться, что он работает так, как вы задумали.

При написании команды архивирования, вы должны иметь в виду, что имена файлов для архивирования могут быть до 64 символов в длину и могут содержать любые комбинации из ASCII символов, цифр и точек. Оригинальный относительный путь (%p) сохранять необязательно, но необходимо сохранять имя файла (%f).

Обратите внимание, что несмотря на то, что архивирование WAL позволяет вам сохранить любые изменения данных, сделанные в вашей базе данных PostgreSQL, архивирование не восстанавливает изменения, внесённые в конфигурационные файлы (такие как postgresql.conf, pg_hba.conf и pg_ident.conf), поскольку эти изменения выполняются вручную, а не через SQL. Вы можете захотеть сохранять кофигурационные файлы в то же место, куда вы будете делать регулярные резервные копии файловой системы. См. Section 18.2 на предмет того, как перемещать конфигурационные файлы.

Команда архивирования вызывается только при полном заполнении WAL сегментов. Таким образом, если ваш сервер генерирует только небольшой WAL трафиик (или у него продолжительные периоды, формирования WAL сегментов), между завершением транзакций и их безопасным сохранением на архивном носителе может возникать продолжительна задержка. Чтобы ограничить длительность существования неархивированных данных, вы можете установить archive_timeout, чтобы чаше заставлять сервер переключаться на новый файл WAL сегмента. Обратите внимание, что архивированные файлы, которые архивируются после такого такого переключения, продолжают сохранять ту же длину, что и полностью заполненные файлы. Таким образом, устанавливать очень короткий archive_timeout — неразумно; это приведёт к увеличению объёма архивируемых данных на архивном носителе. Обычно разумно установить archive_timeout в значение минута или около того.

Также, вы можете заставить переключиться WAL сегмент вручную с помощью pg_switch_xlog, если вы получить уверенность, что только что завершённая транзакция будет архивирована так быстро, как только это возможно. Другие полезные функции, относящиеся к управлению WAL перечисляются в Table 9-56.

Когда wal_level установлено в значение minimal, некоторые команды SQL работают в обход журналирования WAL, как описывается в Section 14.4.7. Если архивирование или потоковая репликация была включена во время выполнения таких операторов, WAL не будет содержать необходимую информацию для восстановления. (Восстановление после краха не даст эффекта). По данной причине, wal_level может быть изменён только при запуске сервера. Однако, archive_command может быть изменена при перезагрузке конфигурационного файла. Если вы хотите временно остановить архивирование, одним из способов сделать это, является установка значения archive_command в пустую строку (''). Это приведёт к накоплению WAL файлов в pg_xlog/, пока не будет восстановлена работа archive_command.

24.3.2. Выполнение базовой резервной копии

Процедура выполнения базовой резервной копии относительно проста:

  1. Убедитесь, что архивирование WAL включено и в работает.

  2. Подключитесь к базе данных как суперпользователь и выполните команду:

    SELECT pg_start_backup('метка');

    где метка — это любая строка, которую вы хотите использовать как уникальный идентификатор данной операции резервного копирования. (Хорошей практикой является использование полного пути, куда вы планируете разместить файл дампа с резервной копией.) pg_start_backup создаёт в каталоге кластера файл с меткой резервного копирования, называемый backup_label, содержащий информацию о вашей резервной копии, включая время начала и строку с меткой.

    Для выполнения этой команды, неважно к какой базе данных в кластере вы подключаетесь. Вы можете игнорировать результат, возвращаемый данной функцией; но если он говорит об ошибке, разберитесь с ней перед тем как продолжить.

    По умолчанию, выполнение pg_start_backup может занять длительное время. Так происходит, потому что функция выполняет контрольную точку (checkpoint) и операции ввода/вывода, требуемые для выполнения этого действия будут занимать значительный период времени, по умолчанию половину вашего интервала между контрольными точками (см. конфигурационный параметр checkpoint_completion_target). Обычно, это то, что вам нужно, потому что такое поведение минимизирует влияение на обработку запросов. Если же вы хотите запустить резервное копирование как можно скорее, используйте:

    SELECT pg_start_backup('метка', true);

    Что заставит завершится котрольную точку как можно быстрее.

  3. Выполните резервное копирование, используя подходящий инструмент резервного копирования для файловой системы, такой как tar или cpio (не pg_dump или pg_dumpall). Пока вы это делаете останавливать нормальную работу сервера баз данных не нужно и нежелательно.

  4. Снова подключитесь к базе данных как суперпользователь и выполните команду:

    SELECT pg_stop_backup();

    Она завершит работу режима резервного копирования и выполнит автоматическое переключение на следующий WAL сегмент. Причина переключения состоит в выравнивании последнего файла с WAL сегментом, работавшим во время выполнения резервного копирования, с целью подготовки к архивации.

  5. Как только заархивируется файлы с WAL сегментами, появившиеся во время резервного копирования, вы закончили. Файл, идентифицируемый функцией pg_stop_backup, является последним сегментом, который требуется для полного списка файлов резервной копии. Если включена переменная archive_mode, функция pg_stop_backup не завершится пока последний сегмент не будет заархивирован. Архивирование этих файлов происходит автоматически, поскольку у вас уже настроена команда archive_command. В большинстве случаев, это происходит быстро, но вы сверяйтесь с монитором вашей системы архивирования, чтобы убедиться в отсутствии задержек. Если процесс архивирования остаёт из-за ошибок команды архивации, попытки архивации будут продолжаться пока архивация не будет успешно выполнена, а резервная копия завершена. Если вы хотите установить лимит времени на выполнение pg_stop_backup, установите соответствующее значения в statement_timeout.

Для получения резервной копии, вы также можете использовать инструмент pg_basebackup, вместо ручного копирования файлов. Этот инструмент будет автоматически выполнять действия эквивалентные шагам, включающим вызов функции pg_start_backup(), копирование и вызов функции pg_stop_backup(), а также передачу резервной копии через обычное соединение к PostgreSQL, с помощью протокола репликации, вместо требуемого доступа на уровне файловой системы. pg_basebackup не пересекается с с резервными копиями на уровне файловой системы, полученными с помощью pg_start_backup()/pg_stop_backup().

Некоторые инструменты резервного копирования файловой системы выдают предупреждения или ошибки, если файлы, которые они пытаются скопировать были изменены во время процесса копирования. Когда выполняется базовое резервное копирование на активной базе данных, данная ситуация является нормальной и не является ошибкой. Однако, вы должны убедиться, что вы можете отличать ошибки такого рода от реальных ошибок. Например, некоторые версии rsync возвращают отдельный код выхода для ситуации "исчезнувшие исходные файлы", и вы можете написать скрипт, который воспринимает этот код выхода как неошибочный. Также, некоторые версии GNU tar возвращают код выхода неотличимый от кода фатальной ошибки, если файл был усечён во время его копирвования с помощью tar. К счастью, GNU tar версий 1.16 и более поздних, завершает работу с кодом 1, если файл был изменён во время копирования и 2 в случае других ошибок.

Нет необходимости беспокоиться о времени, которое прошло между pg_start_backup и фактическим началом резервного копирования, или которое прошло между окончанием резервного копирования и pg_stop_backup; несколько минут задержки никакого вреда не нанесут. (Однако, если вы обычно запускаете сервер баз данных с выключенным параметром full_page_writes, вы можете обратить внимание на потерю производительности между вызовом pg_start_backup и pg_stop_backup, поскольку full_page_writes эффективно работает во время резервного копирования.) Вы должны убедиться, что эти шаги осуществляются последовательно, без какого-либо возможного перекрывания друг друга, иначе вы получите нерабочую резервную копию.

Убедитесь, что ваш дамп резервной копии включает все файлы из каталога кластера баз данных (например, /usr/local/pgsql/data). Если вы используете табличные пространства, которые находяется не внутри этого каталога, убедитесь, что они также включены в резервную копию (и убедитесь, что при создании резервной копии символьные ссылки сохранились как ссылки, иначе при восстановлении вы повредите ваши табличные пространства).

Однако, вы можете опустить из дампа резервной копии файлы из каталога кластера баз данных, которые находятся в подкаталоге pg_xlog/. Об этой незначительной поправке говориться, потому что она снижает риск ошибок во время восстановления. И это легко устроить, если pg_xlog/ является символьной ссылкой, указывающей на какое-либо место за пределами каталога с кластером баз данных, который, что обычно и делается из соображений производительности.

Чтобы использовать резервную копию вам необходимо сохранить все файлы с WAL сегментами, сгенерированные во время и после резервного копирования файловой системы. Чтобы помочь вам сделать это, функция pg_stop_backup создаёт файл с историей резервного копирования, который немедленно сохраняется в архивной области WAL. Данный файл получает имя после первого файла с сегментом WAL, который нужен вам для резервного копирования файловой системы. Например, если начальный WAL файл назывался 0000000100001234000055CD, файл с историей резервного копирования получит имя 0000000100001234000055CD.007C9330.backup. (Вторая часть имени файла обозначает точную позицию внутри WAL файла и обычно может быть проигнорирована.) Как только вы получили резервную копию файловой системы и файлов с WAL сегментами, которые были сгенерированы во время данной резервной копии (как задано в файле истории резервного копирования), все архивированные WAL сегменты с меньшими номерными именами, больше не нужны для восстановления из резервной копии и могут быть удалены. Однако, вы должны рассмотреть возможность хранения нескольких резервных копий, чтобы иметь абсолютную уверенность, что вы можете восстановить ваши данные.

Файл истории резервного копирования — это просто маленький текстовый файл. Он содержит строку с меткой, которую вы предоставили функции pg_start_backup, а также начальное и конечное время WAL сегментов резервной копии. Если вы использовали данную метку для идентификации связанного с ней файла дампа, то архивированного файла истории достаточно, чтобы сказать вам о том, какой файл дампа нужен для восстановления.

Поскольку вы должны хранить все архивированные WAL файлы с момента последней базовой резервной копии, интервал между базовым резервным копированием, обычно, должен быть выбран так, чтобы учитывать как много места на устройстве хранения вы хотите выделить для архивирования WAL файлов. Вы также должны рассмотреть как долго вы будете выполнять восстановление, в процессе восстановления будет необходимо воспроизвести все сохранённые WAL сегменты и это может происходить долго, если с момента последней резервной копии прошло много времени.

Также, ничего страшного, что файл с именем backup_метка, который создаёт функция pg_start_backup в каталоге с кластером баз данных, удаляется функцией pg_stop_backup. Данный файл, разумеется, будет заархивирован как часть файла дампа резервной коппи. Файл с меткой включает метку-строку, которую вы указали для pg_start_backup, а также время в которое была запущена функция pg_start_backup и имя начального WAL файла. В случае путаницы, таким образом, можно заглянуть внутрь файла дампа резервной копии и точно определить, из какой сессии резервного копирования создан этот файл дампа.

Также, возможно создать дамп резервной копии, когда сервер остановлен. В этом случае, вы очевидно не используете pg_start_backup или pg_stop_backup, и таким образом используете свои собственные методы для отслеживания версий дампов и связанных с ними WAL файлов. Обычно, всё-таки лучше следовать процедуре непрерывного архивирования, описанной выше.

24.3.3. Восстановление из резервной копии непрерывного архивирования

Итак, наихудшее случилось и вам необходимо восстановиться из резервной копии. Порядок таков:

  1. Остановите сервер баз данных, если он запущен.

  2. Если у вас есть место, чтобы сделать это, скопируйте весь текущий каталог кластера баз данных и все табличные пространства во временный каталог на случай, если они вам потом понадобятся. Обратите внимание, что данная предосторожность требует, чтобы у вас было достаточно свободного дискового пространства, чтобы разместить две копии ваших существующих данных. Если у вас нет достаточного места, вы должны по крайней мере сохранить содержимое подкаталога pg_xlog из каталога кластера баз данных, так как он может содержать журналы, которые не были заархивированы перед остановом сервера.

  3. Удалите все существующие файлы и подкаталоги из каталога кластера баз данных и данные из подкаталогов, содержащих табличные пространства, которые вы используете (если эти подкаталоги расположены вне каталога с кластером баз данных).

  4. Восстановите файлы из вашей резервной копии файловой системы. Убедитесь, что они восстановились с правильными правами доступа и правильными владельцем и группой (системным пользователем баз данных, а не root!). Если вы используете табличные пространства (которые расположены вне каталога с кластером баз данных), вы должны проверить, что символьные ссылки в pg_tblspc/ восстановились корректно.

  5. Удалите все файлы из pg_xlog/; они попали туда из резервной копии файловой системы и таким образом, предположительно, являются более старыми, чем текущие. Если вы не архивировали сам pg_xlog/, то пересоздайте этот каталог с правильными правами доступа или воссоздайте символьную ссылку, если ранее у вас было настроено так.

  6. Если у вас есть незаархивированные файлы с WAL сегментами, которые вы сохранили на втором шаге, скопируйте их в pg_xlog/. (Лучше всего именно скопировать их, а не перенести, чтобы у вас осталось неизменённое состояние ваших старых данных, если вдруг случиться проблема и вам понадобиться выполнять всё заново.)

  7. Создайте командный файл восстановления recovery.conf в каталоге кластера баз данных (см. Chapter 26). Вы можете также захотеть временно изменить pg_hba.conf, чтобы предотвратить подключение обычных пользователей во время восстановительных работ.

  8. Запустите сервер. Сервер войдёт в режим восстановления и начнёт читать необходимые ему архивированные WAL файлы. Если восстановление было прервано из-за внешней ошибки, сервер можно просто перезапустить и он продолжит восстановление. По завершению процесса восстановления, сервер переименует файл recovery.conf в recovery.done (чтобы предотвратить повторный запуск режима восстановления) и затем начнёт обычные операции работы с базами данных.

  9. Просмотрите содержимое ваших баз данных, чтобы убедиться, что вы восстановились на желаемое состояние. Если нет, вернитесь к первому шагу. Если всё хорошо, разрешите подключения вашим пользователям, восстановив старый файл pg_hba.conf.

Ключевая часть всего этого заключается в том, чтобы создать конфигурационный файл для восстановления, который описывает, что вы хотите восстановить и как долго должно быть запущено восстановление. Вы можете использовать в качестве прототипа файл recovery.conf.sample (обычно находящийся после установки в каталоге share/). Одна совершенно необходимая вещь, которую нужно указать в recovery.conf — это команда restore_command, которая говорит PostgreSQL о том, как получать архивированные WAL файлы-сегменты. Как и archive_command, это командная строка для shell. Она может содержать параметр %f, заменяемый на имя нужного файла журнала и параметр %p, который заменяется на путь для копирования этого файла. (Путь является относительным к текущему рабочему каталогу, т.е. каталог с кластером данных). Если вам нужно использовать в команде сам символ %, используйте %%. Простейшая команда может выглядеть так:

restore_command = 'cp /mnt/server/archivedir/%f %p'

которая будет копировать заархивированные ранее WAL сегменты из каталога /mnt/server/archivedir. Разумеется, вы можете использовать что-то более сложное, предположительно даже shell-скрипт, который обращается к оператору для монтирования соответствующей ленты.

Важно, чтобы данная команда возвращала ненулевой код возврата в случае ошибки. Если команда будет вызвана, чтобы затребовать файлы, которых нет в архиве; она должна вернуть при вызове ненулевой код. Это не является условием ошибки. Не все запрашиваемые файлы будут WAL сегментами; вы также должны ожидать запроса файлов с суффиксом .backup или .history. Также, убедитесь, что базовое имя пути %p будет отличаться от %f; не думайте, что они взаимозаменяемы.

WAL сегменты, которые не найдутся в архиве будут искаться в pg_xlog/; это позволяет использовать последние неархивированные сегменты. Однако, сегменты, которые доступны в архиве, будут использованы в предпочтительном порядке, перед файлами в pg_xlog/. При восстановлении заархивированных файлов, система не будет перезаписывать существующее содержимое pg_xlog/.

Обычно, восстановление будет выполняться с использованием всех доступных WAL сегментов, тем самым восстанавливая базу данных к текущему моменту времени (или как можно ближе к нему, исходя из доступных данных WAL сегментов). Таким образом, обычно, восстановление завершится с сообщением "файл не найден (file not found)", точный текст сообщения об ошибке зависит от вашего выбора в restore_command. Вы также можете увидеть сообщение об ошибке при старте восстановления для файла с именем, похожим на 00000001.history. Это также нормально и обычно не говорит о какой-либо проблеме при восстановлении; см. обсуждение в Section 24.3.4.

Если вы хотите восстановиться на какой-то момент времени (скажем, перед тем как неопытный администратор базы данных удалил вашу основную таблицу транзакций), просто укажите требуемую точку останова в recovery.conf. Вы можете указать точку останова, называемую обычно "целью восстановления (recovery target)", или с помощью даты/времени, которым соответствует имя точки восстановления, или в дополнение, указать идентификатор транзакции. Возможность использовать дату/временя, которым соответствует имя точки восстановления, является очень полезной, так как не существует инструментов, которые бы могли вам помочь идентифировать с какой-либо точностью, какой идентификатор транзакции нужно использовать.

Note: Точка останова должна следовать после времени окончания базового резервного копирования, т.е. времени окончания pg_stop_backup. Вы не можете использовать базовую резервную копию для восстановления на какой-либо момент времени, когда резервная копия ещё только создавалась. (Чтобы восстановить на такой момент времени, вы должны вернуться к предыдущей базовой резервной копии и накатывать вперёд из неё.)

Если при восстановлении обнаружены повреждённые данные WAL, восстановление будет остановлено на этой точке и сервер не будет запущен. В этом случае процесс восстановления может быть перезапущен сначала, с указанием "цели восстановления" на момент перед точкой повреждения, так чтобы восстановление могло нормально завершиться. Если восстановление завершается ошибкой в силу какой-либо внешней причины, такой как крах системы или если архив WAL стал недоступен, то восстановление может быть просто перезапущено и оно будет перезапущено всегда с того места, где случилась ошибка. Перезапуск восстановления работает по принципу, сходному с контрольными точками, использующимися при нормальной работе: сервер периодически принудлительно сохраняет своё состояние на диск и затем обновляет файл pg_control, чтобы отменить, что уже обработанные данные WAL не нуждаются в повторном сканировании.

24.3.4. Шкала времени

Возможность восстановить базу данных на некий предыдущий момент времени создаёт некоторые сложности, которые сродни историям из научной фантастики о путешествиях во времени и параллельных мирах. Например, предположим, что в первоначальной истории базы данных, вы удалили критичную таблицу в 17:15 вечера вторника, но не заметили этой ошибки до полудня среды. Невдумчиво, вы взяли вашу резервную копию, восстановили на момент времени в 17:14 вечера вторника и запустили сервер. В этой истории мира базы данных, вы никогда не удаляли вышеупомянутую таблицу. Но предположим, что позже заметили, что это была не такая уж хорошая идея и захотели вернуться ко времени утра среды относительно первоначальной истории базы данных. Вы не сможете сделать это, если при запуске сервера баз данных (уже после восстановления), он перезаписал некоторые файлы WAL-сегментов, номера которых хронологически приводят нас к моменту времени, на который вы хотите откатится сейчас. Таким образом, чтобы избежать этого, вам необходимо как-то различать серии WAL записей, сгенерированные после восстановления на какой-то момент времени от тех, которые были сгенерированы в первоначальной истории базы данных.

Чтобы работать с этой проблемой, у PostgreSQL есть такое понятие как шкала времени. Всякий раз, когда завершается восстановление из архива, для идентификации серий WAL записей, генерируемых после этого восстановления, создаётся новая шкала времени. Номер идентификатора (ID) шкалы времени — это часть имени файлов WAL-сегментов, так что новая шкала времени не перезаписывает WAL-данные, сгенерированные предыдущими шкалами времени. Фактически, возможно архивирование множества разных шкал времени. Хотя можно подумать, что это бесполезная возможность, на самом деле это часто настоящий спасательный круг. Рассмотрим ситуацию, когда вы не полностью уверены в том, какая точка времени должна быть выбрана для восстановления и таким образом должны выполнить несколько пробных и ошибочных восстановлений, пока найдёте лучшее место ответвления от старой истории. Без шкал времени, такой процесс быстро приведёт к неконтролируемому беспорядку. А благодаря шкалам времени, вы можете восстановиться на любое предыдущее состояние, включая состояния в ветках шкал времени, которые вы забраковали ранее.

Каждый раз, когда создаётся новая шкала времени, PostgreSQL создаёт файл "истории шкалы времени", который показывает какая шкала времени ответвилась из предыдущей и когда. Эти файлы истории необходимы, чтобы позволить системе найти правильные файлы с WAL-сегментами при восстановлении из архива, содержащего несколько шкал времени. Таким образом, они архивируются в область WAL архивов, просто как и файлы сегментов WAL. Файлы истории — это просто маленькие текстовые файлы, так что их хранение незатратно (в отличие от файлов сегментов, которые имеют большой размер). Если хотите, вы можете добавлять в файл истории комментарии, чтобы сохранить в них свои собственные заметки о том как и почему была создана данная отдельная шкала времени. Такие комментарии будут особенно значимы, когда у вас дебри из разных шкал времени, полученные в результате экспериментов.

Поведение по умолчанию при восстановлении заключается в восстановлении той же шкалы времени, которая является текущей на момент получения бащовой резервной копии. Если вы хотите восстановить какую-либо шкалу времени, которая вляется её потомком (то есть, если вы хотите вернуть некоторое состояние, которое само было сгенерировано после попытки восстановления), вам необходимо указать идентификатор целевой шкалы времени в recovery.conf. Вы не можете восстановить шкалу времени, которая является более ранним ответвлением, чем базовая резервная копия.

24.3.5. Советы и примеры

Некоторые советы по настройке непрерывного архивирования даются здесь.

24.3.5.1. Автономные горячие резервные копии

В PostgreSQL можно использовать резервное копирование для создания автономных горячих резервных копий. Эти копии не могут быть использованы для восстановления на определённый момент времени, а также обычно работают много быстрее при резервном копировании и восстановлении, чем дампы pg_dump. (Они также намного больше, чем дампы pg_dump, так что в некоторых случаях, преимущество в скорости может стать отрицательным фактором.)

Для подготовки к созданию автономных горячих резервных копий, установите переменную wal_level в archive (или hot_standby), переменную archive_mode в on и настройте команду archive_command, которая выполняет архивирование только, когда существует файл-переключатель. Например:

archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/archive/%f && cp %p /var/lib/pgsql/archive/%f)'

Данная команда выполнять архивирование, когда будет существовать файл /var/lib/pgsql/backup_in_progress, а в противном случае просто вернёт нулевой код возврата (позволяя PostgreSQL зациклить ненужный WAL файл).

После такой подготовки, резервное копирование будет осуществляться с помощью подобного скрипта: following:

touch /var/lib/pgsql/backup_in_progress
psql -c "select pg_start_backup('hot_backup');"
tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/
psql -c "select pg_stop_backup();"
rm /var/lib/pgsql/backup_in_progress
tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/

Сперва создаётся файл-переключатель /var/lib/pgsql/backup_in_progress, включая архивирование заполенных WAL файлов. После окончания резервного копирования файл-переключатель удаляется. Заархивированные WAL файлы затем добавляются в резервную копию, так что и базовая резервная копия и все требуемые WAL файлы, будут находиться в одном и том же файле tar. Пожалуйста, не забудьте добавить к вашим скриптам резервного копирования обработку ошибок.

Если вас беспокоит размер устройства хранения, используйте для удаления ненужных full_page_writes и пустого пространства из WAL файлов, команду pg_compresslog, http://pglesslog.projects.postgresql.org. Вы можете затем использовать gzip, чтобы сжать вывод pg_compresslog:

archive_command = 'pg_compresslog %p - | gzip > /var/lib/pgsql/archive/%f'

Во время восстановления вам понадобятся gunzip и pg_decompresslog:

restore_command = 'gunzip < /mnt/server/archivedir/%f | pg_decompresslog - %p'

24.3.5.2. Скрипты archive_command

Многие люди выбирают в команде archive_command использование скриптов, так что запись в postgresql.conf выглядит очень просто:

archive_command = 'local_backup_script.sh'

Использование отдельного файла скрипта является целесообразным в том случае, если вы хотите использовать в процессе архивирования более, чем одну команду. Это позволяет реализовывать внутри скрипта любые вещи, которые можно написать на любом популярном скриптовом языке, таком как bash или perl. Любые сообщения, отправляемые из скрипта на stderr, будут записываться в журнал сервера баз данных, позволяя лёгко диагностировать ошибки в сложных конфигурациях.

Примеры необходимых вещей, которые могут быть реализованы с помощью скрипта включают:

  • Копирование данных на безопасное внешнее устройство хранения

  • Создание пакета WAL файлов, чтобы они передавались каждые три часа, а не по одному

  • Взаимодействие с другим программным обеспечением резервного копирования и восстановления

  • Взаимодействие с программным обеспечением мониторинга для отслеживания ошибок

24.3.6. Предостережения

Как уже было описано, существует несколько ограничений для технологии непрерывного архивирования. Предположительно, они будут исправлены в будущих версиях:

  • Операции на хэшированных индесах не попадают в WAL, так что воспроизведение WAL не изменит эти индексы. Это будет означать, что любые новые вставки будут проигноированы индексом, обновлённые строки вероятно будут исчезать и будут оставаться указатели на удалённые строки. Другими словами, если вы изменяете таблицу с имеющимся хэшированным индексом, то вы будете получать некорректные результаты запросов на резервном сервере. Когда восстановление завершится, рекомендуется ручное выполнение REINDEX на каждый такой индекс.

  • Если команда CREATE DATABASE выполняется во время выполнения базового резервного копирования и затем происходит копирование шаблонной базы данных, которая указана в CREATE DATABASE, а затем эта шаблонная база данных изменяется пока продолжается выполнение резервного копирования, возможно, что восстановление приведёт к тому, что эти изменения распространятся также и на созданную базу данных. Конечно, это нежелательно. Чтобы избежать подобного риска, лучше всего не изменять никаких шаблонных баз данных во время выполнения базового резервного копирования.

  • Команды CREATE TABLESPACE попадают в WAL с абсолютным путём и таким образом при воспроизведении WAL будут выполнены с этим же абсолютным путём. Это может быть нежелательно, если журнал воспроизводится на другой машине. Это может быть опасно, даже если журнал воспроизводится на той же машине, но в новом каталоге с данными: воспроизведение будет перезаписывать содержимое оригинальных табличных пространств. Чтобы избежать потенциальных проблем такого вида, лучшей практикой является создание новой базовой резервной копии после создания или удаления табличных пространств.

Так нужно отметить, что по умолчанию формат WAL является довольно громоздким, так как включает много снимков дисковых страниц. Эти снимки страниц разрабатывались для поддержки восстановления после краха, так как они могут понадобиться для исправления дисковых страниц, записанных частично. В зависимости от аппаратного и программного обеспечения вашей системы, риск частичной записи может быть настолько маленьким, что его можно игнорировать и в этом случае можно существенно уменьшить общий объём архивируемых журналов, выключив снимки страниц с помощью параметра full_page_writes. (Перед тем, как сделать это, прочтите замечания и предупреждения в Chapter 29.) Выключение снимков страниц не предотвратит использование журналов для PITR операций. Направлением для будущей разработки является сжатие архивирумых WAL данных, с помощью удаления ненужных копий страниц, даже когда full_page_writes включен. В настоящее время, администраторы могут захотеть уменьшить количество снимков страниц, включаемых в WAL, увеличив насколько это возможно, параметры интервала между выполненеием контрольных точек.

Back to top

(С) Виктор Вислобоков, 2008-2023