PGSQL 08: Бэкапы

Описание:

Если какая-нибудь неприятность может произойти, она обязательно случится — Закон Мэрфи.

Всякий хороший системный администратор знает — бэкапы необходимы всегда. Насколько бы надежной ни казалась ваша система, всегда может произойти случай, который был не учтен и из-за которого могут быть потеряны данные. Даже если у вас репликация с множеством слейвов, это не значит, что система в безопасности — неверный запрос на мастер (DELETE/DROP/TRUNCATE) — и у слейвов такая же порция данных (точнее их отсутствие). Существуют три принципиально различных подхода к резервному копированию данных PostgreSQL:

  • SQL-бэкап;
  • бэкап уровня файловой системы;
  • непрерывное резервное копирование.

Каждый из этих подходов имеет свои сильные и слабые стороны.

SQL-бэкап (pg_dump)

Идея такого подхода — в создании текстового файла с командами SQL. Данный файл можно передать обратно на сервер и воссоздать базу данных в том же состоянии, в котором она была во время бэкапа. У PostgreSQL для этого есть специальная утилита — pg_dump.

Пример:

$ pg_dump dbname > outfile

Для восстановления такого бэкапа требуется выполнить:

$ psql dbname < infile

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

$ psql --set ON_ERROR_STOP=on dbname < infile

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

$ pg_dump -h host1 dbname | psql -h host2 dbname

После восстановления бэкапа желательно запустить ANALYZE, чтобы оптимизатор запросов обновил статистику.

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

Пример:

$ pg_dumpall > outfile

Для восстановления такого бэкапа достаточно выполнить от супер-пользователя:

$ psql -f infile postgres

SQL-бэкап больших баз данных

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

  • Использовать сжатие для бэкапа.
$ pg_dump dbname | gzip > filename . gz

Восстановление:

$ gunzip -c filename.gz | psql dbname

Или

$ cat filename. gz | gunzip | psql dbname
  • Использовать команду split. split позволяет разделить вывод на файлы меньшего размера, подходящего для файловой системы. Например, бэкап делится на куски по 1 мегабайту:
$ pg_dump dbname | split -b 1m - filename

Восстановление:

$ cat filename* | psql dbname
  • Использовать пользовательский формат дампа pg_dump. PostgreSQL построен на системе с библиотекой сжатия Zlib, поэтому пользовательский формат бэкапа будет в сжатом виде. Это похоже на метод с использованием GZIP, но он имеет дополнительное преимущество — таблицы могут быть восстановлены выборочно. Минус такого бэкапа — восстановить возможно только в такую же версию PostgreSQL (отличаться может только патч релиз, третья цифра после точки в версии). Пример:
$ pg_dump -Fc dbname > filename

Через psql такой бэкап не восстановить, но для этого есть утилита — pg_restore.

$ pg_restore -d dbname filename

При слишком большой базе данных вариант с командой split нужно комбинировать со сжатием данных

Бэкап уровня файловой системы

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

$ tar -cf backup.tar /usr/local/pgsql/data

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

  • PostgreSQL база данных должна быть остановлена, для того чтобы получить актуальный бэкап. PostgreSQL держит множество объектов в памяти. Излишне говорить, что во время восстановления такого бэкапа потребуется также остановить PostgreSQL.
  • Не получится восстановить только определенные данные с такого бэкапа.

Непрерывное резервное копирование

В процессе работы PostgreSQL ведет журнал предзаписи (WAL), о котором поговорим немного позже, когда будем разбирать Point in Time Recovery.

pg_basebackup

pg_basebackup предназначен для создания резервных копий работающего кластера баз данных PostgreSQL. pg_basebackup создает бинарную копию файлов кластера, контролируя режим создания копии автоматически. Резервные копии всегда создаются для кластера целиком и невозможно создать копию для какой-либо сущности базы отдельно. Копия создается через обычное подключение к PostgreSQL, и при этом используется протокол репликации. Подключение должно осуществляться от лица суперпользователя или пользователя с правом REPLICATION, с данным типом бэкапирования мы знакомились при создании реплики в теме 6. При копировании с ведомого сервера есть некоторые ограничения:

  • Файл истории резервного копирования в целевом кластере баз данных не создается.
  • При использовании ключа -X none нет гарантии, что все файлы WAL, требуемые для резервной копии, будут заархивированы в конце копирования.
  • Если ведомый сервер переключается в роль ведущего в процессе копирования, копирование прерывается.
  • Все необходимые для резервной копии WAL-записи должны содержать полные страницы, для чего нужно включить режим full_page_writes на ведущем и не использовать в archive_command такие утилиты, как pg_compresslog, которые могут удалить записанные полные страницы из WAL.

Point in Time Recovery (PITR)

PostgreSQL поддерживает упреждающую запись логов (Write Ahead Log, WAL) в pg_wal директорию, которая находится в директории данных СУБД. В логи пишутся все изменения данных в СУБД. Этот журнал существует прежде всего для безопасности во время краха PostgreSQL (если происходят сбои в системе, базы данных могут быть восстановлены с помощью «перезапуска» этого журнала). Тем не менее, существование журнала делает возможным использование третьей стратегии для резервного копирования баз данных: мы можем объединить бэкап уровня файловой системы с резервной копией WAL-файлов. Если требуется восстановить такой бэкап, то мы восстанавливаем файлы резервной копии файловой системы, а затем «перезапускаем» с резервной копии файлов WAL для приведения системы к актуальному состоянию. Этот подход является более сложным для администрирования, чем любой из ранее описанных, но он имеет некоторые преимущества:

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

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

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

Процесс архивирования файлов WAL

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

Чтобы включить архивирование WAL, необходимо установить в параметре конфигурации wal_level уровень replica (или выше), в archive_mode — значение on и задать желаемую команду оболочки в параметре 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

archive_command будет копировать архивируемые сегменты WAL в каталог /mnt/server/archivedir.

После замены параметров %p и %f фактически запускаемая команда может выглядеть так:

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

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

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

Архивирование WAL позволяет сохранить любые изменения данных, произведенные в базе данных PostgreSQL, оно не затрагивает изменения, внесенные в конфигурационные файлы (такие как postgresql.conf, pg_hba.conf и pg_ident.conf).

Команда архивирования вызывается, только когда сегмент WAL заполнен до конца. Чтобы ограничить время жизни неархивированных данных, можно установить archive_timeout, чтобы сервер переключался на новый файл сегмента WAL как минимум с заданной частотой. В таком случае неполные файлы, архивируемые досрочно из-за принудительного переключения по тайм-ауту, будут иметь тот же размер, что и заполненные файлы. Также вы можете принудительно переключить сегмент WAL вручную с помощью pg_switch_wal, если хотите, чтобы только что завершенная транзакция заархивировалась как можно скорее. Другие полезные функции, относящиеся к управлению WAL, перечисляются в System Administration Functions. Если вы хотите на время остановить архивирование, это можно сделать, например задав в качестве значения archive_command пустую строку (''). В результате файлы WAL будут накапливаться в каталоге pg_wal/, пока не будет восстановлена действующая команда archive_command.

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

Начиная с postgresql-12 прекращена поддержка recovery.conf файла, теперь для активации режима восстановления необходимо наличие одного из файлов (обычно пустых):

  • $PGDATA/recovery.signal — идеологический наследник standby_mode=off, восстановление из архива будет произведено до указанной в конфигах точки;
  • $PGDATA/standby.signal — соответственно, standby_mode=on. Этот файлик мы будем видеть на всех репликах.

Если будут найдены оба файла, то мы попадем в режим standby.

Регламент восстановления резервной копии:

  1. Остановите сервер баз данных, если он запущен.
  2. Если у вас есть место для этого, скопируйте весь текущий каталог кластера баз данных и все табличные пространства во временный каталог на случай, если они вам понадобятся. Учтите, что эта мера предосторожности требует, чтобы свободного места на диске было достаточно для размещения двух копий существующих данных. Если места недостаточно, необходимо сохранить как минимум содержимое подкаталога pg_wal каталога кластера, так как он может содержать журналы, не попавшие в архив перед остановкой системы.
  3. Удалите все существующие файлы и подкаталоги из каталога кластера и из корневых каталогов используемых табличных пространств.
  4. Восстановите файлы базы данных из резервной копии файлов. Важно, чтобы у восстановленных файлов были правильные разрешения и правильный владелец. Если вы используете табличные пространства, убедитесь также, что символьные ссылки в pg_tblspc/ восстановились корректно.
  5. Удалите все файлы из pg_wal/; они восстановились из резервной копии файлов и поэтому, скорее всего, будут старее текущих. Если вы вовсе не архивировали pg_wal/, создайте этот каталог с правильными правами доступа, но если это была символьная ссылка, восстановите ее.
  6. Если на шаге 2 вы сохранили незаархивированные файлы с сегментами WAL, скопируйте их в pg_wal/. (Лучше всего именно копировать, а не перемещать их, чтобы у вас остались неизмененные файлы на случай, если возникнет проблема и все придется начинать сначала).
  7. Создайте командный файл восстановления recovery.signal/standby.signal в каталоге кластера баз данных. Вы можете также временно изменить pg_hba.conf, чтобы обычные пользователи не могли подключаться, пока вы не будете уверены, что восстановление завершилось успешно.
  8. Запустите сервер. Сервер запустится в режиме восстановления и начнет считывать необходимые ему архивные файлы WAL. Если восстановление будет прервано из-за внешней ошибки, сервер можно просто перезапустить и он продолжит восстановление.
  9. Просмотрите содержимое базы данных, чтобы убедиться, что вы вернули ее к желаемому состоянию. Если это не так, вернитесь к шагу 1. Если все хорошо, разрешите пользователям подключаться к серверу, восстановив обычный файл pg_hba.conf.

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

Пример:

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

Эта команда копирует заархивированные ранее сегменты WAL из каталога /mnt/server/archivedir.

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

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

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

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

WAL-E

WAL-E предназначена для непрерывной архивации PostgreSQL WAL- logs в Amazon S3 или Windows Azure (начиная с версии 0.7) и управления использованием pg_start_backup и pg_stop_backup. Утилита написана на Python и разработана в компании Heroku, где ее активно используют. Установка: У WAL-E есть пара зависимостей:

  • lzop;
  • psql;
  • pv (в старых версиях используется mbuffer);
  • python 3.4+ и несколько python библиотек (gevent, boto , azure). Также для удобства настроек переменных среды устанавливаются daemontools.

На Ubuntu это все можно поставить одной командой:

$ apt install aptitude
$ aptitude install git-core python-dev python-setuptools python-pip build-essential libevent-dev lzop pv daemontools daemontools-run

В системах, основанных на Red Hat, необходимо установить пакет EPEL для соответствующей платформы со следующего URL-адреса:

https://fedoraproject.org/wiki/EPEL

Например для CentOS 7:

yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

Затем выполнить следующие команды для pip3:

sudo yum update -y
sudo yum install python3 lzop pv -y
sudo yum install python36-setuptools -y
yum install python36-devel
alias pip=pip3

Если возникли проблемы с pip3, то выполняем команды:

yum install python36
yum install python36-devel
yum install python36-setuptools
easy_install-3.6 pip
pip3 -V
alias pip=pip3

Теперь установим WAL-E:

pip install https://github.com/wal-e/wal-e/archive/v1.1.1.tar.gz

После успешной установки можно начать работать с WAL-E.

Настройка и работа с WAL-E

  1. Используем pip3 для установки WAL-E и дополнительных утилит среды:
yum install gcc
sudo pip3 install wal-e envdir
  1. Установим необходимый облачный драйвер WAL-E (в нашем случае Amazon) с помощью команды:
sudo pip3 install boto
sudo python3 -c 'import boto; print(boto.__path__[0])' | xargs -I{} sudo chmod -R a+rx {}
  1. Создадим каталог конфигурации, доступный для чтения пользователю системы postgres:
sudo mkdir -m 0750 -p /etc/wal-e/env
sudo chgrp -R postgres /etc/wal-e
  1. Как пользователь с полномочиями root, установим несколько переменных среды с помощью следующих команд:
sudo -i
umask u=rwx,g=r,o=  #Чтобы не светить ключи от AWS
echo 'key-id' > /etc/wal-e/env/AWS_ACCESS_KEY_ID 
echo 'key-value' > /etc/wal-e/env/AWS_SECRET_ACCESS_KEY
echo 'bucket-path' > /etc/wal-e/env/WALE_S3_PREFIX
echo 'aws-region' > /etc/wal-e/env/AWS_REGION
chgrp postgres /etc/wal-e/env/*

Пример:

sudo -i
umask u=rwx,g=r,o=
echo 'AKIASJOX4ZWFEA3DW3J7' > /etc/wal-e/env/AWS_ACCESS_KEY_ID 
echo 'C7FSBk6bygORc4vkGPO5dHl++6UopDHD462PQkiK' > /etc/wal-e/env/AWS_SECRET_ACCESS_KEY
echo 's3://task08test' > /etc/wal-e/env/WALE_S3_PREFIX
echo 'eu-west-2' > /etc/wal-e/env/AWS_REGION
chgrp postgres /etc/wal-e/env/*

Рассмотрим, что было сделано

Мы начинаем с использования pip3 для фактической установки WAL-E.

Затем мы создаем каталог для хранения файлов конфигурации для WAL-E. Эта часть не является строго необходимой, но WAL-E зависит от довольно большой части конфиденциальной информации. Он должен проходить аутентификацию на сервере облачного хранилища для каждого взаимодействия. Самый безопасный способ сделать это — сохранить несколько файлов, доступных для чтения только пользователю системы postgres. Единственная альтернатива — вызвать команду wal-e, передав эти значения вручную.

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

В случае переменной WALE_S3_PREFIX важно использовать только путь к корзине, которую мы создали ранее, и необязательно каталог. Если бы мы назвали нашу корзину postgres-ha-cookbook и добавили каталог wal, мы бы использовали s3://postgres-ha-cookbook/wal для WALE_S3_PREFIX.

Когда мы создавали корзину, нам было разрешено выбрать регион, в котором серверы Amazon будут фактически хранить наши данные. WAL-E должен знать, где находятся эти серверы, поэтому, по крайней мере в случае Amazon S3, нам нужно установить переменную AWS_REGION. Регион по умолчанию — us-east-1, но правильный регион для нашего сегмента должен быть указан в интерфейсе AWS S3.

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

Управление файлами WAL с помощью WAL-E

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

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

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

Как это работает?

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

  1. Отредактируем файл postgresql.conf, чтобы отразить настройки параметров:
wal_level = 'replica' 
archive_mode = 'on' 
archive_command = 'envdir /etc/wal-e/env wal-e wal-push %p' 
archive_timeout = '60'
  1. Перезапустим службу PostgreSQL с помощью следующей команды от имени пользователя postgres:
systemctl restart postgresql-13

В логе должны увидеть:

$ systemctl status postgresql-13
$ tail -f /var/log/postgresql.log 
        STRUCTURED: time=2021-01-19T21:05:09.572015-00 pid=1690 action=push-wal key=s3://task08test/wal_005/000000010000000000000007.lzo prefix= rate=143.344 seg=000000010000000000000007 state=complete
wal_e.worker.upload INFO     MSG: completed archiving to a file
        DETAIL: Archiving to "s3://task08test/wal_005/000000010000000000000001.lzo" complete at 3082.52KiB/s.
        STRUCTURED: time=2021-01-19T21:05:10.315938-00 pid=1690 action=push-wal key=s3://task08test/wal_005/000000010000000000000001.lzo prefix= rate=3082.52 seg=000000010000000000000001 state=complete
wal_e.worker.upload INFO     MSG: begin archiving a file
        DETAIL: Uploading "pg_wal/000000010000000000000003.00000028.backup" to "s3://task08test/wal_005/000000010000000000000003.00000028.backup.lzo".
        STRUCTURED: time=2021-01-19T21:05:10.874903-00 pid=1704 action=push-wal key=s3://task08test/wal_005/000000010000000000000003.00000028.backup.lzo prefix= seg=000000010000000000000003.00000028.backup state=begin
wal_e.worker.upload INFO     MSG: completed archiving to a file
        DETAIL: Archiving to "s3://task08test/wal_005/000000010000000000000003.00000028.backup.lzo" complete at 0.715094KiB/s.
        STRUCTURED: time=2021-01-19T21:05:11.367965-00 pid=1704 action=push-wal key=s3://task08test/wal_005/000000010000000000000003.00000028.backup.lzo prefix= rate=0.715094 seg=000000010000000000000003.00000028.backup state=complete

img8_1.png

Сначала мы устанавливаем archive_command для вызова утилиты wal-e. Параметр wal-push указывает ему передать файл в наше облачное хранилище и предположить, что это журнал транзакций. Он выполняет некоторые беглые проверки до и после этого, поэтому мы не можем использовать его в качестве общего инструмента для отправки разных файлов в облако.

Далее устанавливаем для archive_timeout значение, отличное от нуля. Если для параметра archive_timeout установлено ненулевое значение, он будет чередовать журналы транзакций по истечении времени, независимо от необходимости.

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

Восстановление журналов WAL

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

Чтобы использовать WAL-E для восстановления удаленно сохраненных журналов транзакций в восстановленную базу данных, начнем с чего-то вроде этого:

standby_mode = 'on' 
restore_command = 'envdir /etc/wal-e/env /usr/local/bin/wal-e wal-fetch "%f" "%p"'

Конечно, это приведет к тому, что наш сервер PostgreSQL будет постоянно спамить облачный сервис с файловыми запросами. Это нормально, пока есть файлы для извлечения, но если мы достигли конца доступных файлов, это просто избыточный трафик по сравнению с нашими облачными квотами. Мы можем избежать этого, используя recovery_target_name, recovery_target_time или recovery_target_xid, чтобы остановить восстановление, как только оно достигнет выбранного пункта назначения.

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

backup-push

WAL-E также может выступать в качестве резервного бэкапирования. Обычно не рекомендуется этого делать, поскольку резервное копирование в удаленное место обычно является довольно дорогостоящим. Это не просто вопрос денежных затрат, тут стоит также учитывать время и задержку. Резервное копирование базы данных объемом 1 ТБ с помощью WAL-E может быть не очень хорошей идеей, но для системы меньшего размера, не превышающей нескольких ГБ, — это может быть идеальным решением.

Лучшее в этой возможности — то, что ее легко вызвать. Сделаем резервную копию нашей базы данных с помощью WAL-E:

envdir /etc/wal-e/env wal-e backup-push /db/pgdata

Пример:

# sudo -u postgres bash -c "/usr/local/bin/envdir /etc/wal-e/env /usr/local/bin/wal-e backup-push /var/lib/pgsql/13/data/"

wal_e.main   INFO     MSG: starting WAL-E
        DETAIL: The subcommand is "backup-push".
        STRUCTURED: time=2021-01-20T18:15:51.785338-00 pid=64127
wal_e.operator.backup INFO     MSG: start upload postgres version metadata
        DETAIL: Uploading to s3://task08test/basebackups_005/base_000000010000000000000011_00000040/extended_version.txt.
        STRUCTURED: time=2021-01-20T18:15:51.923285-00 pid=64127
wal_e.operator.backup INFO     MSG: postgres version metadata upload complete
        STRUCTURED: time=2021-01-20T18:15:52.292306-00 pid=64127
wal_e.worker.upload INFO     MSG: beginning volume compression
        DETAIL: Building volume 0.
        STRUCTURED: time=2021-01-20T18:15:52.408141-00 pid=64127
wal_e.worker.upload INFO     MSG: begin uploading a base backup volume
        DETAIL: Uploading to "s3://task08test/basebackups_005/base_000000010000000000000011_00000040/tar_partitions/part_00000000.tar.lzo".
        STRUCTURED: time=2021-01-20T18:15:52.921034-00 pid=64127
wal_e.worker.upload INFO     MSG: finish uploading a base backup volume
        DETAIL: Uploading to "s3://task08test/basebackups_005/base_000000010000000000000011_00000040/tar_partitions/part_00000000.tar.lzo" complete at 4555.27KiB/s. 
        STRUCTURED: time=2021-01-20T18:15:54.329725-00 pid=64127
NOTICE:  all required WAL segments have been archived

backup-list

С помощью команды backup-list мы можем просмотреть список полных бэкапов на S3.

# sudo -u postgres bash -c "/usr/local/bin/envdir /etc/wal-e/env /usr/local/bin/wal-e backup-list"
wal_e.main   INFO     MSG: starting WAL-E
        DETAIL: The subcommand is "backup-list".
        STRUCTURED: time=2021-01-20T18:26:26.798863-00 pid=64727
name	last_modified	expanded_size_bytes	wal_segment_backup_start	wal_segment_offset_backup_start	wal_segment_backup_stop	wal_segment_offset_backup_stop
base_00000001000000000000000C_00000040	2021-01-20T18:07:25.000Z		00000001000000000000000C	00000040		
base_00000001000000000000000E_00000040	2021-01-20T18:08:07.000Z		00000001000000000000000E	00000040		
base_000000010000000000000011_00000040	2021-01-20T18:15:58.000Z		000000010000000000000011	00000040		

Восстановление из бэкапа

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

envdir /etc/wal-e/env wal-e backup-fetch /db/pgdata LATEST

Пример:

sudo -u postgres bash -c "/usr/local/bin/envdir /etc/wal-e/env /usr/local/bin/wal-e --s3-prefix=s3://task08test backup-fetch /var/lib/pgsql/13/data LATEST"

Эти две команды составляют отличную пару, если у нас нет другого выхода или мы хотим протестировать восстановление на месте. В высокодоступных системах всегда хорошо иметь готовые альтернативы.

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

Для удаления старых резервных копий (или вообще всех) используется команда delete:

# удаление старых бэкапов старше base_00000004000002DF000000A6_03626144
$ envdir /etc/wal-e.d/env wal-e delete --confirm before base_00000004000002DF000000A6_03626144

Удаление всех бэкапов:

$ envdir /etc/wal-e.d/env wal-e delete --confirm everything

Удалить все старше последних 20 бэкапов:

$ envdir /etc/wal-e.d/env wal-e delete --confirm retain 20

Подведем итог работы с WAL-E

WAL-E помогает автоматизировать сбор резервных копий с PostgreSQL и хранить их в достаточно дешевом и надежном хранилище — Amazon S3 или Windows Azure.

Полезные ссылки:

Правила выполнения задания:

  1. Время создания окружения занимает до 5 минут.
  2. После нажатия кнопки «Начать выполнение» для вас будет создано окружение для выполнения задания, состоящее из одной или более виртуальнах машин с Centos-7 Linux. К ним будут выданы IP, логин и пароль для доступа по SSH, а также при необходимости — дополнительных ресурсов.
  3. Также, если необходимо, вам могут быть выданы переменные, которые в задании указаны в фигурных скобках, — их надо будет подставить при выполнении задания (например, ${base_domain}).
  4. После выполнения всех пунктов задания нажмите кнопку «Проверить выполнение», и в течение 3-5 минут скрипт проверит выполнение всех условий и выставит вам оценку.
  5. В случае, если вы что-то забыли, можно исправить ошибку и отправить на проверку повторно (нажав кнопку «Проверить выполнение»).
  6. После получения удовлетворительной оценки нажмите кнопку «Завершить задание», чтобы созданное окружение уничтожилось и вы могли приступить к следующему заданию.
  7. Если у вас закончилось время (истек таймер) — окружение будет автоматически уничтожено и вам придется начать выполнение заново.
  8. Также, если вы успешно сдали задание, но у вас остались вопросы — вы всегда сможете задать их куратору после проверки (используя кнопку «Задать вопрос куратору») или в чате практикума в любое удобное для вас время. Обращаем внимание — кураторы проверяют вопросы в течение 24 часов.

Задание:

  1. Установить postgresql 13 через пакетный менеджер.
  2. Восстановить schema.sql и data.sql из /opt.
  3. Установить пакет EPEL epel-release-latest-7.noarch.rpm.
  4. Установить python3 и pip3.
  5. Установить python3 пакеты:
    • lzop
    • pv
    • python36-setuptools
  6. Установить WAL-E для aws s3.
  7. Установить pip3 расширение boto.
  8. Создать каталог /etc/wal-e/env.
  9. Выставить права на каталог для группы postgres.
  10. Добавить в каталог из п.8 переменные среды:.
# значения переменных для каждого пользователя индивидуальные в инфраструктуре
echo 'key-id' > /etc/wal-e/env/AWS_ACCESS_KEY_ID
echo 'key-value' > /etc/wal-e/env/AWS_SECRET_ACCESS_KEY
echo 'bucket-path' > /etc/wal-e/env/WALE_S3_PREFIX
echo 'eu-central-1' > /etc/wal-e/env/AWS_REGION
  1. Установить envdir.
  2. Настроить архивацию журналов транзакций в файле postgresql.conf.
  3. Убедиться в работоспособности архивации в s3, путем выполнения команды: sudo -u postgres bash -c '/usr/local/bin/envdir /etc/wal-e/env /usr/local/bin/wal-e backup-list' > /tmp/file
  4. Если уверены, что все сделали правильно, отправляйте задание на проверку.

Связаться с нами