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

Надо ли каждый раз резервировать весь кластер?

В начале рассмотрим вопрос практичности — насколько эффективно каждый раз создавать полную резервную копию кластера? Понятно, что это накладно по времени и по ресурсам (как для создания резервной копии, так и для ее хранения). Но также не стоит забывать и про RPO (Recovery Point Objective), что фактически означает какое количество данных может быть потеряно в случае восстановления. Поэтому чем чаще мы можем создавать точки восстановления, тем меньше будет RPO.

RPO и RTO
RPO и RTO

В предыдущей статье мы уже создавали точку восстановления (restore point) по завершению физического резервирования на всех сегментах кластера. Но нам не запрещается создавать такие точки восстановления и после этого. Что это дает? Мы точно также можем восстановиться из имеющейся резервной копии и проиграть WAL лог до новой точки восстановления. Да, объем WAL-лога будет больше, но и данные у нас будут более актуальными. Более подробно про создание точек восстановления можно прочитать тут.

Однако и у этого есть обратная сторона: чем больше промежуток между резервной копией и точкой восстановления, тем больше будет RTO (Recovery Time Objective), поскольку поверх восстановленных файлов надо будет применить больший объем WAL. Идея довольно простая, но тут важно отметить следующее: так как для восстановления на restore point требуется резервная копия, сделанная ранее, и WAL, то при удалении данной резервной копии восстановиться на подобную restore point уже никак не получится. А значит это надо будет учитывать при удалении резервных копий, о чем мы поговорим чуть позже.

Прерывание резервирования

Далее поговорим про обработку прерывания резервирования. Причин может быть масса, но важно правильно обрабатывать подобные ситуации. Сначала зададимся вопросом: если резервирование было прервано, то обязательно ли для его перезапуска начинать все сначала? Ведь мы могли запустить резервирование, которое работало уже весьма продолжительное время, прежде чем произошла остановка (будь то преднамеренная или в случае ошибки). И если бы была возможность повторно запустить резервирование с учетом уже имеющихся данных, то это бы сильно сократило и время, и место (потому что не надо удалять уже полученные данные).

Для обработки подобной ситуации в pgbackrest (а именно эта утилита рассматривалась в предыдущей статье в качестве базы для прототипа ggbm — решения для резервирования) у команды backup есть специальная опция --resume. Делает она буквально следующее: если предыдущий запуск backup был того же типа и не был успешно завершен, то повторный запуск пропустит уже зарезервированные файлы. Исключение составляют те файлы, у которых не соответствует контрольная сумма, и те, которые были сгруппированы в bundle (см. опцию --repo-bundle).

Использование в Greengage такого подхода дополняется следующими нюансами:

  1. Перед запуском стоит проверить в метаданных предыдущей резервной копии ее статус и тип.Если предыдущий запуск backup был успешным, то лучше резервирование запускать с явным указанием опции --no-resume.

  2. Если действительно возможен запуск с опцией --resume, то надо определить на каких сегментах нужен перезапуск. Тут надо рассмотреть следующие варианты относительно предыдущего резервирования:

    • Сегмент не был зарезервирован вовсе. В этом случае перезапускаем с --no-resume.

    • Сегмент не был зарезервирован частично. В этом случае перезапускаем с --resume.

    • Сегмент был успешно зарезервирован. Такие сегменты надо исключить из повторного запуска команды backup.

  3. Прерывание процесса pgbackrest не снимает блокировку резервирования.Для этого надо на каждом сегменте кластера в utility-режиме явно вызвать функцию pg_stop_backup.

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

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

Удаление резервных копий

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

Для начала стоит рассмотреть встроенный в pgbackrest механизм удаления и насколько он применим к Greengage. А конкретно, рассмотрим настройку retention policy. Данный механизм позволяет настроить автоматическое удаление резервных копий после каждого успешного завершения команды backup. В качестве типа можно выбрать между удалением по времени или по количеству. Настраивать число копий можно только для типов full и diff, а инкрементальные копии удаляются вместе с теми копиями, от которых они зависят.

Кроме этого в pgbackrest есть команда expire, которая позволяет: 

  • вызвать процедуру удаления на основании настройки retention;

  • удалить конкретный backup set, даже если он не попадает под условия retention policy (исключение — если это единственная резервная копия в stanza).

В целом, функциональные возможности весьма гибкие и автоматизируют процесс удаления. Но если смотреть на retention policy в pgbackrest со стороны Greengage, то пользоваться ими не получится по следующим причинам:

  • удаление по времени невозможно сделать консистентным на кластере (могут быть удалены лишние backup set  или наоборот, оставлены уже ненужные);

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

Для иллюстрации последнего давайте взглянем на такой пример: выполнили команду backup с типом full. Далее запустили второй раз с тем же типом, но на одном из сегментов произошла ошибка (возможно backup даже не запустился из-за ошибки). Перезапускать backup не стали, а сняли новый backup на всем кластере, но уже типа incr. Теперь у нас для некоторых сегментов число резервных копий типа full отличается. А это значит, что при автоматическом удалении резервных копий в дальнейшем мы можем потерять часть кластерной резервной копии.

Пример снятия невалидной инкрементальной резервной копии из-за ошибки при предыдущем backup
Пример снятия невалидной инкрементальной резервной копии из-за ошибки при предыдущем backup

Как же тогда быть в таком случае? Тут придется управлять процессом удаления вне pgbackrest, для этого надо отключить автоматическое удаление в конфигурации pgbackrest.conf:

expire-auto=n

Сам алгоритм удаления может быть похож на то, как реализовано в pgbackrest:

  • определить последний (по времени) backup set (далее BS) для удаления;

  • определить список backup set, сделанных до BS;

  • определить все зависимые от BS backup set типа diff и incr, которые были сделаны в промежуток после BS и ближайшего к нему backup set типа full;

  • последовательно удалить все backup set, определенные на предыдущих шагах, и связанные с ними архивы WAL через вызов команды expire.

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

Результат удаления конкретной резервной копии (РК) зависит от того, будет ли при этом применяться автоматическое удаление на основе policy. И если да, то будет это до или после. Тут зависит от того, что вы считаете ожидаемым поведением в данном сценарии. 

Удаление РК 'Full 3' с применением политик хранения до удаления
Удаление РК 'Full 3' с применением политик хранения до удаления
Удаление РК 'Full 3' с применением политик хранения после удаления
Удаление РК 'Full 3' с применением политик хранения после удаления

Для полноты картины добавим, что удаление резервной копии типа diff будет выглядеть примерно аналогично удалению копии типа full, но со своими нюансами. А вот удаление инкрементальной резервной копий можно отдельно не рассматривать, поскольку удаляться она будет всегда совместно с full или diff, от которых зависит.

Изменение топологии кластера

В Greengage доступность кластера обеспечивается за счет зеркалирования сегментов. Переключение основного (primary) сегмента на его зеркало (mirror) может произойти как автоматически (например, сбой primary-сегмента), так и планово (остановка сегмент-хоста для проведения технических работ). Но при чем тут резервирование? 

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

Выход тут понятен: нужно получить актуальную топологию кластера (особенно это важно, если кластер уже недоступен), а далее сопоставить метаданные каждого сегмента из резервной копии с его актуальным расположением и восстановить на том хосте, где он последний раз был в статусе primary. Но до запуска кластера важно не забыть о том, что хоть мы и восстановили кластер на нужных хостах, состояние в gp_segment_configuration не будет ему соответствовать. Поэтому надо для начала запустить только master и перезаписать на нем топологию кластера на новое состояние:

pg_ctl start -D /data1/master/gpseg-1/

PGOPTIONS='-c gp_session_role=utility -c allow_system_table_mods=true' psql -d postgres -c "delete from gp_segment_configuration; insert into gp_segment_configuration(...);"

Далее уже можно будет запускать весь кластер:

gpstop -arM fast

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

Итоги

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

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

  • как изменение конфигурации влияет на имеющиеся резервные копии;

  • параллельное восстановление primary- и mirror-сегментов;

  • восстановление одного кластера из резервной копии другого кластера.

Комментарии (0)