Резервное копирование и восстановление

Как и для всего, что содержит ценные данные, для баз данных QHB следует регулярно проводить резервное копирование. Хотя по сути это простая процедура, важно четко понимать лежащие в ее основе методики и предположения.

Существует три принципиально разных подхода к резервному копированию данных в QHB:

  • SQL-дамп

  • Резервное копирование на уровне файловой системы

  • Непрерывное архивирование

У каждого из них есть свои сильные и слабые стороны, которые рассматриваются в следующих разделах.



SQL-дамп

Идея этого метода дампа состоит в том, чтобы создать файл с SQL-командами, которые при передаче обратно на сервер воссоздают базу данных в том же состоянии, в котором она находилась во время создания дампа. QHB предоставляет для этой цели программу-утилиту qhb_dump. Простейшее использование этой программы выглядит следующим образом:

qhb_dump имя_бд > файл_дампа

Как видите, qhb_dump записывает свой результат в стандартный вывод. Ниже мы рассмотрим, чем это может быть полезно. Хотя вышеуказанная команда создает текстовый файл, qhb_dump может создавать файлы и в других форматах, которые допускают параллельную обработку и более точное управление восстановлением объектов.

qhb_dump — обычное клиентское приложение QHB. Это означает, что процедуру резервного копирования можно выполнить с любого удаленного хоста, имеющего доступ к базе данных. Но помните, что qhb_dump работает, не используя специальные разрешения. В частности, ему требуется доступ на чтение ко всем таблицам, для которых выполняется резервное копирование, поэтому для резервного копирования всей базы данных почти всегда требуется запускать ее с правами суперпользователя. (Если у вас недостаточно прав для резервного копирования всей базы данных, вы все равно можете создавать резервные копии тех ее частей, к которым у вас есть доступ, используя такие параметры, как -n схема или -t таблица).

Чтобы указать, к какому серверу баз данных должно обращаться qhb_dump, можно воспользоваться параметрами командной строки -h хост и -p порт. По умолчанию в качестве хоста используется локальный хост или значение, указанное в переменной среды PGHOST. Аналогичным образом порт по умолчанию указывается в переменной среды PGPORT или, если она не задана, значением, принятым по умолчанию. (Для удобства при компиляции серверу обычно по умолчанию назначается то же значение.)

Как и любое другое клиентское приложение QHB, qhb_dump по умолчанию соединяется с базой данных под именем пользователя, совпадающим с именем текущего пользователя операционной системы. Чтобы переопределить это, нужно либо указать параметр -U, либо установить переменную среды PGUSER. Помните, что соединения qhb_dump подчиняются обычным механизмам аутентификации клиента (эти механизмы описаны в главе Аутентификация клиентского приложения).

Важное преимущество qhb_dump перед другими методами резервного копирования, описанными ниже, заключается в том, что выходные данные qhb_dump, как правило, можно загружать в более новые версии QHB, тогда как резервные копии на уровне файлов и непрерывное архивирование жестко привязаны к версии сервера. Кроме того, qhb_dump является единственным методом, который будет работать при переносе базы данных на другую машинную архитектуру, например при переходе с 32-разрядного на 64-разрядный сервер.

Дампы, созданные qhb_dump, внутренне непротиворечивы, то есть дамп представляет собой снимок состояния базы данных на момент запуска qhb_dump. Приложение qhb_dump не блокирует другие операции с базой данных во время своей работы. (Исключение составляют операции, которым требуется исключительная блокировка, как например, большинство форм команды ALTER TABLE.)


Восстановление дампа

Текстовые файлы, созданные qhb_dump, предназначены для чтения программой psql. Общая форма команды для восстановления дампа:

psql имя_бд < файл_дампа

где файл_дампа — это файл, содержащий вывод команды qhb_dump. Эта команда не будет создавать базу данных имя_бд, поэтому ее нужно создать самостоятельно из шаблона базы template0 перед выполнением psql (например с помощью команды createdb -T template0 имя_бд). psql поддерживает аналогичные qhb_dump параметры для указания сервера баз данных, к которому нужно подключиться, и имени пользователя. Подробную информацию см. в справке по psql. Дампы нетекстовых файлов восстанавливаются с помощью утилиты qhb_restore.

Перед восстановлением SQL-дампа все пользователи, которым в выгруженной базе данных принадлежали объекты или права на них, уже должны существовать. Если их нет, при восстановлении не удастся воссоздать объекты с первоначальными владельцами и/или правами. (Иногда это желаемое поведение, но обычно это не так).

По умолчанию скрипт psql будет продолжать выполняться даже после возникновения ошибки SQL. Если запустить psql с переменной ON_ERROR_STOP, установленной для изменения этого поведения, то при ошибке SQL psql завершится кодом 3:

psql --set ON_ERROR_STOP=on имя_бд < файл_дампа

В любом случае, у вас будет только частично восстановленная база данных. В качестве альтернативы можно указать, что весь дамп должен быть восстановлен за одну транзакцию, чтобы восстановление либо полностью завершилось, либо полностью отменилось. Этот режим можно указать, передав в psql параметры командной строки -1 или --single-transaction. При использовании этого режима помните, что даже небольшая ошибка может послужить причиной отката восстановления, выполняющегося уже в течение многих часов. Однако, возможно, это все же предпочтительнее, чем вручную чистить сложную базу данных после частично восстановленного дампа.

Способность qhb_dump и psql использовать каналы ввода/вывода позволяет скопировать базу данных напрямую с одного сервера на другой, например:

qhb_dump -h хост1 имя_бд | psql -h хост2 имя_бд

ВАЖНО!
Дампы, создаваемые qhb_dump, связаны с базой template0. Это означает, что любые языки, процедуры и т. д., добавленные через template1, также будут выгружены qhb_dump. В результате при восстановлении, если вы используете настроенный template1, следует создать пустую базу данных из template0, как показано в примере выше.

После восстановления резервной копии целесообразно запустить ANALYZE для каждой базы данных, чтобы оптимизатор запросов имел полезную статистику. Дополнительную информацию см. в подразделах Обновление статистики планировщика и Процесс «Автовакуум». Дополнительные советы о том, как эффективно загружать большие объемы данных в QHB, см. в разделе Заполнение базы данных.


Использование qhb_dumpall

qhb_dump одновременно создает дамп только одной базы данных и не включает в него информацию о ролях или табличных пространствах (потому что она относится ко всему кластеру, а не к самой базе данных). Для удобства создания дампа всего содержимого кластера баз данных предусмотрена программа qhb_dumpall. qhb_dumpall выполняет резервное копирование каждой базы данных в заданном кластере, а также сохраняет данные уровня кластера, например определения ролей и табличных пространств. Простой вариант использования этой программы:

qhb_dumpall > файл_дампа

Полученный дамп можно восстановить с помощью psql:

psql -f файл_дампа qhb

(На самом деле в качестве начальной базы можно указать имя любой существующей базы данных, но если вы загружаете в пустой кластер, обычно следует использовать qhb.) Восстановление дампа qhb_dumpall необходимо проводить с правами суперпользователя, поскольку это требуется для восстановления информации о ролях и табличных пространствах. Если вы используете табличные пространства, убедитесь, что их пути в дампе соответствуют новой среде.

qhb_dumpall работает, выполняя команды для воссоздания ролей, табличных пространств и пустых баз данных, а затем вызывая qhb_dump для каждой базы данных. Это означает, что хотя каждая база данных будет внутренне согласованной, снимки разных баз данных не синхронизируются.

Данные уровня кластера можно выгрузить отдельно, используя параметр --globals-only. Это необходимо для полного резервного копирования кластера при выполнении команды qhb_dump в отдельных базах данных.


Обработка больших баз данных

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

Используйте сжатые дампы. Вы можете использовать предпочитаемую программу сжатия, например, gzip:

qhb_dump имя_бд | gzip > имя_файла.gz

Восстановить дамп можно так:

gunzip -c имя_файла.gz | psql имя_бд

или так:

cat имя_файла.gz | gunzip | psql имя_бд

Используйте split. Команда split позволяет разбить вывод на более мелкие файлы, приемлемые по размеру для нижележащей файловой системы. Например, чтобы сделать куски по 2 гигабайта:

qhb_dump имя_бд | split -b 2G - имя_файла

Восстановить дамп можно так:

cat имя_файла* | psql имя_бд

Разбивку GNU можно использовать вместе с gzip:

qhb_dump имя_бд | split -b 2G --filter='gzip > $FILE.gz'

Восстановить такой дамп можно командой zcat.

Используйте специальный формат дампа qhb_dump. Если QHB была собрана в системе с установленной библиотекой сжатия zlib, пользовательский формат дампа будет сжимать данные по мере их записи в выходной файл. Вследствие этого размер файла дампа будет такой же, как при использовании gzip, но у него есть дополнительное преимущество: таблицы можно восстанавливать выборочно. Следующая команда создает дамп базы данных в специальном формате:

qhb_dump -Fc имя_бд > имя_файла

Дамп в специальном формате не является скриптом для psql, его следует восстанавливать с помощью qhb_restore, например:

qhb_restore -d имя_бд имя_файла

Подробную информацию см. в справке по утилитам qhb_dump и qhb_restore.

Для очень больших баз данных может потребоваться объединить split с одним из двух других подходов.

Используйте функцию параллельного дампа qhb_dump. Чтобы ускорить дамп большой базы данных, можно воспользоваться параллельным режимом qhb_dump. Этот режим позволит сбросить несколько таблиц одновременно. С помощью параметра -j можно управлять количеством потоков. Параллельные дампы поддерживаются только для архива в формате каталога.

qhb_dump -j число -F d -f выходной.каталог имя_бд

Для восстановления дампа в параллельном режиме можно использовать qhb_restore -j. Это будет работать для любого архива, созданного в специальном формате или в формате каталога, независимо от того, был ли он создан командой qhb_dump -j.



Резервное копирование на уровне файловой системы

Альтернативная стратегия резервного копирования заключается в прямом копировании файлов, которые QHB использует для хранения данных в базе; в разделе Создание кластера баз данных объясняется, где расположены эти файлы. Для резервного копирования файловой системы можно использовать любой метод, например:

tar -cf backup.tar /var/lib/qhb/data

Однако есть два ограничения, которые делают этот метод непрактичным или, по крайней мере, уступающим методу qhb_dump:

  1. Сервер баз данных должен быть выключен, чтобы получить правильную резервную копию. Промежуточные меры, такие как запрещение всех подключений, работать не будут (отчасти потому, что tar и подобные инструменты не делают атомарный снимок состояния файловой системы, но еще и из-за буферизации внутри сервера). Информацию об остановке сервера можно найти в разделе Завершение работы сервера. Излишне говорить, что перед восстановлением данных сервер также необходимо выключить.

  2. Выполнить резервное копирование или восстановление только отдельных таблиц или баз данных из их соответствующих файлов или каталогов невозможно, потому что информацию, содержащуюся в этих файлах, нельзя использовать без файлов журнала транзакций pg_xact/*, которые содержат статус фиксации всех транзакций. Файл таблицы можно использовать только с этой информацией. Конечно, также невозможно восстановить только таблицу и связанные данные pg_xact, потому что это сделает все остальные таблицы в кластере баз данных бесполезными. Таким образом, резервные копии файловой системы работают только для полного резервного копирования и восстановления всего кластера баз данных.

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

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

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

Другой вариант — использовать для резервного копирования файловой системы rsync. Для этого нужно сначала запустить rsync во время работы сервера баз данных, а затем завершить работу сервера баз данных на время, достаточное, чтобы выполнить rsync --checksum. (Ключ --checksum необходим, потому что rsync различает время с точностью только до секунд). Второй запуск rsync отработает быстрее, чем первый, потому что ему останется относительно мало данных для передачи, и конечный результат будет согласованным, поскольку сервер был выключен. Этот метод позволяет выполнять резервное копирование файловой системы с минимальным временем простоя.

Обратите внимание, что резервная копия файловой системы обычно больше, чем SQL-дамп. (Например, qhb_dump не нужно записывать содержимое индексов, только команды для их восстановления). Однако создание резервной копии файловой системы может выполняться быстрее.



Непрерывное архивирование и восстановление на момент времени (PITR)

QHB поддерживает журнал упреждающей записи (WAL) в подкаталоге pg_wal/ каталога данных кластера. В журнал записываются все изменения, внесенные в файлы данных базы. Этот журнал существует главным образом в целях обеспечения безопасности при сбоях: в случае сбоя системы базы данных можно восстановить до состояния согласованности путем «воспроизведения» записей журнала, созданных с момента последней контрольной точки. Однако наличие журнала позволяет использовать третью стратегию резервного копирования баз данных: можно объединить резервное копирование на уровне файловой системы с резервным копированием файлов WAL. Если требуется восстановление, то чтобы привести систему к актуальному состоянию, сначала восстанавливается резервная копия файловой системы, а затем воспроизводятся изменения из резервных копий файлов WAL. Этот подход сложнее в управлении, чем любой из предыдущих подходов, но он имеет некоторые существенные преимущества:

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

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

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

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

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

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

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


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

В абстрактном смысле работающая система QHB создает бесконечно длинную последовательность записей WAL. Система физически делит эту последовательность на файлы сегментов WAL, которые обычно имеют размер 16 МБ (хотя размер сегмента можно изменить во время создания нового кластера базы данных с помощью qhb_bootstrap (или initdb)). Сегменты получают числовые имена, которые отражают их положение в абстрактной последовательности WAL. Когда архивация WAL не используется, система обычно создает только несколько файлов сегментов, а затем «перерабатывает» их, меняя имена ставших ненужными файлов WAL на новые, с бо́льшими номерами. Предполагается, что файлы сегментов, содержимое которых предшествует последней контрольной точке, больше не представляют интереса и могут быть использованы повторно.

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

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

archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'  # Unix

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

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

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

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

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

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

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

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

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

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

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

Обратите внимание, что несмотря на то, что архивация WAL позволит вам восстановить любые изменения, внесенные в данные в вашей базе данных QHB, она не восстановит изменения, внесенные в файлы конфигурации (то есть qhb.conf, qhb_hba.conf и qhb_ident.conf), так как они редактируются вручную, а не с помощью операций SQL. Вам может понадобиться сохранить файлы конфигурации в том же месте, где будут храниться результаты ваших обычных процедур резервного копирования файловой системы. Как перемещать файлы конфигурации, описывается в разделе Расположение файлов.

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

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

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


Создание базовой резервной копии

Самый простой способ выполнить базовое резервное копирование — использовать инструмент qhb_basebackup. Он может создавать базовую резервную копию в виде обычных файлов или в виде архива tar. Альтернативой этому инструменту служит qbackup. Эта программа позволяет сохранять ваши резервные копии в структурированный каталог, при этом поддерживается инкрементальное копирование и сжатие, а также параллельный режим работы.

Если требуется больше гибкости, чем могут обеспечить эти программы, можно создать базовую резервную копию, используя низкоуровневый API (см. раздел Создание базовой резервной копии с использованием API низкого уровня).

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

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

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

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


Создание базовой резервной копии с использованием API низкого уровня

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

Резервные копии низкого уровня можно создать монопольным или немонопольным способом. Рекомендуется применять немонопольный способ, поскольку монопольный является устаревшим и в будущем будет убран.


Создание немонопольной резервной копии на низком уровне

Немонопольное резервное копирование низкого уровня позволяет запускать другие параллельные резервные копии (через API или qhb_basebackup).

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

  2. Подключитесь к серверу (не имеет значения, к какой базе данных) как пользователь с правами на запуск pg_start_backup (суперпользователь или пользователь, наделенный правом EXECUTE для этой функции) и выполните команду:

    SELECT pg_start_backup('label', false, false);
    

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

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

    Если третий параметр равен false, это указывает pg_start_backup запустить немонопольное базовое резервное копирование.

  3. Выполните резервное копирование, используя любой удобный инструмент для резервного копирования файловой системы, например tar или cpio (не qhb_dump или qhb_dumpall). Останавливать при этом нормальную работу базы данных необязательно и нецелесообразно. Нюансы, которые следует учитывать при выполнении этого резервного копирования, описаны в подразделе Резервное копирование каталога данных.

  4. В том же соединении, что и раньше, введите команду:

    SELECT * FROM pg_stop_backup(false, true);
    

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

    Функция pg_stop_backup вернет одну строку с тремя значениями. Второе из этих полей должно быть записано в файл с именем backup_label в корневом каталоге резервной копии. Третье поле должно быть записано в файл с именем tablespace_map, если это поле не пустое. Эти значения крайне важны для резервного копирования и должны быть записаны без изменений, для чего может понадобиться открыть файл в двоичном режиме.

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

    Если процесс резервного копирования отслеживает и обеспечивает успешную архивацию всех файлов сегментов WAL, необходимых для резервного копирования, то для параметра wait_for_archive (по умолчанию он равен true) можно установить значение false, чтобы функция pg_stop_backup завершалась, как только запись остановки резервного копирования протоколируется в WAL. По умолчанию pg_stop_backup будет ждать окончания архивации всех файлов WAL, что может занять некоторое время. Этот параметр следует использовать с осторожностью: если архивирование WAL не контролируется должным образом, резервная копия может включать не все файлы WAL и, следовательно, окажется неполной и не сможет быть восстановлена.


Создание монопольной резервной копии на низком уровне

Примечание
Монопольный метод резервного копирования устарел, и его следует избегать.

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

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

  2. Подключитесь к серверу (не имеет значения, какой базы данных) как пользователь с правами на выполнение pg_start_backup (суперпользователь или пользователь, наделенный правом EXECUTE для этой функции) и выполните команду:

    SELECT pg_start_backup('label');
    

    где label — любая строка, которую вы хотите использовать для уникальной идентификации этой операции резервного копирования. Функция pg_start_backup создает в каталоге кластера файл метки резервной копии с именем backup_label, содержащий информацию о вашей резервной копии, включая время начала и строку метки. Эта функция также создает в каталоге кластера файл карты табличных пространств с именем tablespace_map, содержащий информацию о символических ссылках табличных пространств в pg_tblspc/, если имеется одна или несколько таких ссылок. Оба файла имеют решающее значение для целостности резервной копии, если она понадобится вам для восстановления.

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

    SELECT pg_start_backup ('label', true);
    

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

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

    Как отмечалось выше, если во время резервного копирования происходит сбой сервера, перезапуск может оказаться невозможным, пока файл backup_label не будет вручную удален из каталога PGDATA. Обратите внимание, что очень важно никогда не удалять файл backup_label при восстановлении из резервной копии, поскольку это приведет к повреждению данных. Непонимание того, когда именно следует удалить этот файл, является распространенной причиной повреждения данных при использовании этого метода. Убедитесь, что вы удаляете файл только на существующем основном сервере, и никогда не удаляйте его при создании резервного сервера или при восстановлении из резервной копии, даже если вы создаете резервный сервер, который впоследствии будет преобразован в новый основной сервер.

  4. Снова подключитесь к базе данных как пользователь с правами на выполнение pg_stop_backup (суперпользователь или пользователь, наделенный правом EXECUTE для этой функции) и выполните команду:

    SELECT pg_stop_backup();
    

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

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

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


Резервное копирование каталога данных

Некоторые инструменты резервного копирования файловой системы выдают предупреждения или ошибки, если файлы, которые они пытаются скопировать, в процессе копирования изменяются. При создании базовой резервной копии активной базы данных это нормальная ситуация, а не ошибка. Однако следует убедиться, что вы можете отличить сообщения такого рода от реальных ошибок. Например, некоторые версии rsync возвращают отдельный код завершения для «исчезнувших исходных файлов», и можно написать управляющий скрипт, чтобы принять этот код завершения как не ошибочный. Кроме того, некоторые версии GNU tar возвращают код ошибки, неотличимый от фатальной ошибки, если файл был усечен во время его копирования через tar. К счастью, GNU tar версии 1.16 и выше завершается с кодом 1, если файл был изменен во время резервного копирования, и с кодом 2 для других ошибок. В GNU tar версии 1.23 и выше можно использовать параметры предупреждений --warning=no-file-changed и --warning=no-file-removed, чтобы скрыть соответствующие сообщения с предупреждениями.

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

Однако следует исключить из резервной копии файлы в подкаталоге кластера pg_wal/. Эта небольшая корректировка имеет смысл, поскольку снижает риск ошибок при восстановлении. Это легко организовать, если pg_wal/ представляет собой символическую ссылку, указывающую за пределы каталога кластера — в любом случае такую настройку часто делают из соображений производительности. Также можно исключить qhbmaster.pid и qhbmaster.opts, которые записывают информацию о работающем qhbmaster, а не о том qhbmaster, который в конечном итоге будет использовать эту резервную копию. (Эти файлы могут запутать qhb_ctl).

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

Содержимое каталогов pg_dynshmem/, pg_notify/, pg_serial/, pg_snapshots/, pg_stat_tmp/ и pg_subtrans/ (но не сами эти каталоги) можно исключить из резервной копии, поскольку оно будет инициализировано при запуске qhbmaster. Если параметр stats_temp_directory установлен и указывает на подкаталог внутри каталога данных, то содержимое этого каталога также можно опустить.

Также из резервной копии можно исключить любой файл или каталог, начинающийся с pgsql_tmp. Эти файлы удаляются при запуске qhbmaster, а каталоги будут воссоздаваться по мере необходимости.

Файлы pg_internal.init можно исключать из резервной копии всякий раз, когда найден файл с таким именем. Эти файлы содержат данные кэша отношений, которые всегда воссоздаются при восстановлении.

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

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


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

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

  1. Остановите сервер, если он работает.

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

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

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

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

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

  7. Задайте параметры конфигурации восстановления в qhb.conf (см. подраздел Восстановление из архива) и создайте файл recovery.signal в каталоге данных кластера. Кроме того, можно временно изменить qhb_hba.conf, чтобы обычные пользователи не могли подключаться, пока вы не убедитесь, что восстановление прошло успешно.

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

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

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

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

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

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

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

Сегменты WAL, которые нельзя найти в архиве, система будет искать в pg_wal/; это позволяет использовать последние неархивированные сегменты. Однако у сегментов, доступных из архива, будет приоритет перед файлами из pg_wal/.

Обычно восстановление проходит через все доступные сегменты WAL, тем самым восстанавливая базу данных до текущего момента времени (или максимально близко, учитывая доступные сегменты WAL). Поэтому нормальное восстановление заканчивается сообщением «файл не найден» (точный текст сообщения об ошибке зависит от выбора restore_command). Также сообщение об ошибке может появиться в начале восстановления для файла с именем вроде 00000001.history. Это тоже нормально и не говорит о проблеме в простых ситуациях восстановления; это описывается в подразделе Временная шкала.

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

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

Примечание
В команде restore в qbackup существуют параметры, позволяющие выбрать эти настройки. Ими можно будет воспользоваться, только если резервная копия была создана при помощи backup.

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


Временная шкала

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

Чтобы справиться с этой проблемой, в QHB есть понятие временная шкала. Всякий раз по завершении восстановления архива создается новая временная шкала для определения последовательности записей WAL, сгенерированной после этого восстановления. Идентификационный номер временной шкалы входит в состав имен файлов сегментов WAL, поэтому новая временная шкала не перезаписывает данные WAL, созданные предыдущими временными шкалами. На самом деле можно архивировать множество различных временных шкал. Хотя это может показаться бесполезным свойством, зачастую оно оказывается спасительным. Рассмотрим ситуацию, когда вы не совсем уверены, к какому моменту времени необходимо восстановить базу данных, и поэтому вам приходится методом проб и ошибок делать несколько попыток восстановления на определенный момент времени, пока не найдется лучшее место для ветвления из старой истории. Без временных шкал этот процесс быстро приведет к неуправляемому беспорядку. С помощью временных шкал можно восстановить любое предыдущее состояние, в том числе состояния в ветвях временных шкал, от которых вы отказались ранее.

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

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


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

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

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

Для создания автономных оперативных резервных копий можно использовать средства резервного копирования QHB. Это резервные копии, которые нельзя использовать для восстановления на определенный момент времени, но, как правило, ими гораздо быстрее выполнять резервное копирование и восстановление, чем дампами qhb_dump. (Они также гораздо больше дампов qhb_dump, поэтому в некоторых случаях преимущество в скорости может быть сведено на нет.)

Как и в случае базовых резервных копий, самый простой способ создать автономную горячую резервную копию — использовать инструмент qhb_basebackup. Если при вызове этой утилиты задать параметр -X, в резервную копию будет автоматически включен весь журнал упреждающей записи, необходимый для ее использования, и никаких специальных действий для ее восстановления не потребуется.

Если при копировании файлов резервных копий требуется больше гибкости, для автономных горячих резервных копий также можно использовать процесс более низкого уровня. Чтобы подготовиться к получению низкоуровневой автономной горячей резервной копии, обязательно задайте для параметра wal_level значение replica или выше, для параметра archive_mode значение on и настройте команду archive_command, которая выполняет архивирование только при наличии файла-переключателя. Например:

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

Примечание
В qbackup для этих целей имеется подкоманда backup-wal; подробную информацию см. в подразделе qbackup backup-wal.

Эта команда выполнит архивирование, если существует файл /var/lib/qhb/backup_in_progress, а в противном случае молча вернет нулевой статус выхода (что позволит QHB переработать ненужный файл WAL).

С такой подготовкой резервную копию можно сделать с помощью скрипта наподобие следующего:

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

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

Существует альтернативный подход к горячему резервному копированию в виде утилиты qbackup. Эта утилита комбинирует архивирование WAL-записей и постраничное инкрементальное резервное копирование, что позволяет добиться более компактных резервных копий за счет сохранения только тех данных, которые изменились с момента создания предыдущей автономной резервной копии.


Сжатие архивных журналов

Если размер архивного хранилища вызывает обеспокоенность, можно сжать архивные файлы с помощью gzip:

archive_command = 'gzip < %p > /var/lib/qhb/archive/%f'

Затем во время восстановления нужно будет использовать gunzip:

restore_command = 'gunzip < /mnt/server/archivedir/%f > %p'

Скрипты archive_command

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

archive_command = 'local_backup_script.sh "%p" "%f"'

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

Примеры задач, которые могут быть решены в скрипте:

  • Копирование данных в безопасное внешнее хранилище.

  • Пакетное копирование WAL, чтобы они передавались каждые три часа, а не по одному.

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

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

Совет
При использовании в archive_command скрипта желательно включить logging_collector. Любые сообщения, записанные в stderr из скрипта, затем появятся в журнале сервера баз данных, позволяя легко диагностировать сбои в сложных конфигурациях.

Примечание
Также для этих целей можно использовать qbackup backup-wal.


Ограничения применимости

На момент написания документации методика непрерывного архивирования имеет несколько ограничений. Вероятно, это будет исправлено в следующих версиях:

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

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

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