image

Привет, я Александр Никитин, главный системный администратор компании «БАРС Груп». В этой статье я хочу познакомить вас с инструментом pg_probackup.

Pg_probackup — разработка компании Postgres Professional, которая помогает делать резервные копии СУБД PostgreSQL. В отличие от стандартной утилиты pg_basebackup этот инструмент позволяет создавать инкрементные резервные копии на уровне блоков данных (по умолчанию 8Kb), производить валидацию резервных копий и СУБД, задавать политики хранения и многое другое.

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

Будут рассмотрены следующие варианты использования:

  • создание автономных бэкапов на отдельном сервере
  • создание архива wal-файлов и создание бэкапов в этом режиме
  • развёртывание реплики из бэкапа и настройка создания бэкапов с реплики
  • различные варианты восстановления

Задача 1


Дано: У нас есть два сервера (OS CentOS 7), на первом у нас располагается наша база данных (имя хоста srv_db1, пользователь postgres, установлен PostgreSQL 12.4), а на втором мы будем хранить бэкапы (имя хоста srv_bkp, пользователь backup_user).
Необходимо настроить резервное копирование таким образом, чтобы копии кластера PostgreSQL хранились на сервере srv_bkp.

Решение:
pg_probackup умеет работать через ssh, запуская на удаленном хосте агентов, которые используют ssh соединение как канал связи и транспорта. Соответственно, нужно сделать так, чтобы пользователь backup_user на хосте srv_bkp мог подключаться к пользователю postgres на хосте srv_db1.

1) Подключаемся к srv_bkp пользователем backup_user и выполняем следующие команды:

ssh-keygen -t rsa
ssh-copy-id postgres@srv_db1

Включим режим параноика и отредактируем файл ~/.ssh/authorized_keys на сервере srv_db1
Перед строчкой с ключами вставим следующее:

command="pg_probackup-12 agent"

Таким образом, должно получиться что-то вроде этого:
command="pg_probackup-12 agent" ssh-rsa AAAA....

Этим мы говорим, что ничего кроме «pg_probackup-12 agent» запускать через SSH нельзя (подробнее об этом можно прочитать тут).

2) Производим установку pg_probackup на обе машины (в примере мы работаем на CentOS, но для остальных дистрибутивов процесс установки описан в документации):

yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
rpm -ivh https://repo.postgrespro.ru/pg_probackup/keys/pg_probackup-repo-centos.noarch.rpm
yum install pg_probackup-12
yum install pg_probackup-12-debuginfo

Установится последняя доступная версия pg_probackup, на момент написания статьи — 2.4.2.

3) на srv_bkp создаём алиас (это не обязательно, но так удобнее) и определяем переменную, содержащую путь до директории с резервными копиями (предварительно создав эту директорию):

mkdir /home/backup_user/backup_db
echo "BACKUP_PATH=/home/backup_user/backup_db">>~/.bash_profile
echo "export BACKUP_PATH">>~/.bash_profile
echo "alias pg_probackup='pg_probackup-12'">>~/.bash_profile

подгружаем профиль

. .bash_profile

4) на srv_bkp инициализируем каталог резервных копий и добавляем новый экземпляр:

pg_probackup init

Добавляем экземпляр PostgreSQL в каталог, даём ему имя db1, указываем параметры подключения по ssh — хост, имя пользователя, и путь до PGDATA.

pg_probackup add-instance --instance=db1 --remote-host=srv_db1 --remote-user=postgres --pgdata=/var/lib/pgsql/12/data

Если появилась строка

INFO: Instance 'db1' successfully inited

Значит инициализация прошла успешно.
Определим политику удержания резервных копий:

pg_probackup set-config --instance db1 --retention-window=7 --retention-redundancy=2

Получившая политика сводится к следующему:

необходимо удерживать все резервные копии младше 7 дней
при этом кол-во полных резервный копий должно быть не меньше двух

5) Для создания резервных копий необходимо подключение к СУБД, поэтому создаём в кластере PostgreSQL базу, к которой будет происходить подключение для управления процессом резервного копирования (с точки зрения безопасности это лучше, чем подключаться к продуктовой БД), а также изменяем параметры базы данных:

$ createdb backupdb

присоединяемся к новой базе данных

psql -d backupdb

создаём роль БД, от имени которой будет осуществляться управление процессом резервного копирования:

BEGIN;
CREATE ROLE backup WITH LOGIN REPLICATION password 'Strong_PWD';
GRANT USAGE ON SCHEMA pg_catalog TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup(boolean, boolean) TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_create_restore_point(text) TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_switch_wal() TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_last_wal_replay_lsn() TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_current() TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO backup;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_checkpoint() TO backup;
COMMIT;

Обратим внимание на параметр listen_addresses:

show listen_addresses;

если localhost, то меняем на *

alter system set listen_addresses='*';

Если вы изменили listen_addresses то необходимо рестартовать PostgreSQL.

Посмотрим, где у нас расположен файл pg_hba.conf

psql –c 'show hba_file'

Добавим следующие правила в pg_hba.conf:

# pg_probackup access permission
host    backupdb   backup          srv_bkp        md5
host    replication  backup          srv_bkp        md5

Перечитываем конфигурацию:
psql -c 'select pg_reload_conf()'

Проверяем — не было ли опечаток:

psql -c 'select * from pg_hba_file_rules'

На srv_bkp в домашней директории пользователя backup_user cоздаём файл, в котором прописываем имя сервера или его ip-адрес, порт, имя базы, имя пользователя и его пароль. Этот файл нужен для того, чтобы при создании резервной копии пароль вводился автоматически.

echo "srv_db1:5432:replication:backup:Strong_PWD">>~/.pgpass
echo "srv_db1:5432:backupdb:backup:Strong_PWD">>~/.pgpass

Устанавливаем необходимые права на доступ к этому файлу

chmod 600 ~/.pgpass

И создаём первую резервную копию:

pg_probackup backup --instance=db1 -j2 --backup-mode=FULL --compress --stream --delete-expired --pguser=backup --pgdatabase=backupdb --remote-host=srv_db1 --remote-user=postgres

Если мы всё сделали правильно, то на экране появится что-то вроде этого:

INFO: Backup start, pg_probackup version: 2.4.2, instance: db1, backup ID: QFERC9, backup mode: FULL, wal mode: STREAM, remote: true, compress-algorithm: zlib, compress-level: 1
WARNING: This PostgreSQL instance was initialized without data block checksums. pg_probackup have no way to detect data block corruption without them. Reinitialize PGDATA with option '--data-checksums'.
INFO: PGDATA size: 3373MB
INFO: Start transferring data files
INFO: Data files are transferred, time elapsed: 1m:0s
INFO: wait for pg_stop_backup()
INFO: pg_stop backup() successfully executed
INFO: Syncing backup files to disk
INFO: Backup files are synced, time elapsed: 1s
INFO: Validating backup QFERC9
INFO: Backup QFERC9 data files are valid
INFO: Backup QFERC9 resident size: 975MB
INFO: Backup QFERC9 completed
INFO: Evaluate backups by retention
INFO: Backup QFERC9, mode: FULL, status: OK. Redundancy: 1/2, Time Window: 0d/7d. Active
INFO: There are no backups to merge by retention policy
INFO: There are no backups to delete by retention policy
INFO: There is no WAL to purge by retention policy

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

Ознакомимся с текущими настройками:

pg_probackup show-config --instance db1

Теперь давайте сократим команду создания бэкапов — пропишем часть параметров в конфигурацию экземпляра db1:

pg_probackup set-config --instance=db1 --remote-host=srv_db1 --remote-user=postgres --pguser=backup --pgdatabase=backupdb --log-filename=backup_cron.log --log-level-file=log --log-directory=/home/backup_user/backup_db/log

Сравним: как было и как стало

pg_probackup show-config --instance db1

Было Стало
# Backup instance information
pgdata = /var/lib/pgsql/12/data
system-identifier = 6863327140287059463
xlog-seg-size = 16777216
# Connection parameters
pgdatabase = backup_user

# Replica parameters
replica-timeout = 5min
# Archive parameters
archive-timeout = 5min
# Logging parameters
log-level-console = INFO
log-level-file = OFF
log-filename = pg_probackup.log

log-rotation-size = 0TB
log-rotation-age = 0d
# Retention parameters
retention-redundancy = 2
retention-window = 7
wal-depth = 0
# Compression parameters
compress-algorithm = none
compress-level = 1
# Remote access parameters
remote-proto = ssh
# Backup instance information
pgdata = /var/lib/pgsql/12/data
system-identifier = 6863327140287059463
xlog-seg-size = 16777216
# Connection parameters
pgdatabase = backupdb
pghost = srv_db1
pguser = backup

# Replica parameters
replica-timeout = 5min
# Archive parameters
archive-timeout = 5min
# Logging parameters
log-level-console = INFO
log-level-file = LOG
log-filename = backup_cron.log
log-directory = /home/backup_user/backup_db/log

log-rotation-size = 0TB
log-rotation-age = 0d
# Retention parameters
retention-redundancy = 2
retention-window = 7
wal-depth = 0
# Compression parameters
compress-algorithm = none
compress-level = 1
# Remote access parameters
remote-proto = ssh
remote-host = srv_db1
remote-user = postgres



Сделаем инкрементальную копию в DELTA режиме, не указывая установленные в конфиге параметры:

pg_probackup backup --instance=db1 -j2 --progress -b DELTA --compress --stream --delete-expired

Посмотрим, что у нас получилось
BACKUP INSTANCE 'db1'
=====================================================================================================================================
 Instance  Version  ID      Recovery Time           Mode   WAL Mode  TLI   Time   Data   WAL  Zratio  Start LSN   Stop LSN    Status
=====================================================================================================================================
 db1       12       QFERKZ  2020-08-21 05:55:52-04  DELTA  STREAM    1/1     9s  136kB  32MB    1.00  0/B0000028  0/B0000168  OK
 db1       12       QFERC9  2020-08-21 05:51:34-04  FULL   STREAM    1/0  1m:3s  959MB  16MB    3.52  0/AE000028  0/AE0001A0  OK 

Информации довольно много, подробное описание можно встретить в документации, тем не менее давайте остановимся на некоторых пунктах:

Recovery Time — минимальное время, на которое можно восстановиться, используя эту резервную копию

Mode — режим, в котором была сделана копия, на данный момент доступно 4 режима — один полный (FULL) и три инкрементальных (PAGE, DELTA и PTRACK)

WAL Mode — тут возможны следующие варианты — STREAM и ARCHIVE. Копии, созданные в режиме STREAM содержат внутри себя все необходимые для восстановления до консистентного состояния WAL файлы. Как раз для работы этого режима и нужно было дать роль REPLICATION нашему пользователю backup. Режим ARCHIVE подразумевает, что мы настроили архивирование WAL, и тогда необходимые WAL файлы будут лежать по известному pg_probackup пути.

Status — статусов достаточно много, все они описаны в документации, но если мы видим что-то отличное от OK, то есть смысл сходить в документацию и посмотреть что же пошло не так.

Как вы уже догадались, мы можем распарсить вывод команды pg_probackup show и достать статус последнего сделанного бэкапа, обработать его и послать в систему мониторинга, а там уже настроить правила, по которым будет срабатывать оповещение ответственных за СУБД сотрудников.

Создадим скрипт bkp_base.sh, который будет запускать резервное копирование и отправлять результат в систему мониторинга:

#! /bin/sh
# подгружаем профиль с настройками
. /home/backup_user/.bash_profile
# вызываем команду создания копии, в качестве параметра передаем метод создания бэкапа (FULL, DELTA и т.д.)
pg_probackup backup --instance=db1 -j 2 --progress -b $1 --compress --stream --delete-expired 
# Получаем статус последней копии и отправляем его в zabbix.
if [ "$(pg_probackup show --instance=db1 --format=json | jq -c '.[].backups[0].status')" == '"OK"' ]; then
  result=0;
else
  result=1;
fi
# в zabbix уже должен быть создан элемент данных типа zabbix_trapper и ключом pg.db_backup
# Логику обработки полученного значения я предлагаю вам настроить самостоятельно, например может учитываться не только значение, которое пришло, но и время с момента последнего обновления этого элемента.
/opt/zabbix/bin/zabbix_sender -c /opt/zabbix/etc/pg.zabbix_agentd.conf -k pg.db_backup -o $result

Записываем в crontab вызов полученного скрипта, например, можно задать такое расписание:

00 01 * * 7 /home/backup_user/scr/bkp_base.sh FULL
00 01 * * 1,2,3,4,5,6 /home/backup_user/scr/bkp_base.sh DELTA

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

В следующей части мы рассмотрим создание архива wal-файлов и создание архивных резервных копий.