Привет, я Александр Никитин, главный системный администратор компании «БАРС Груп». В этой статье я хочу познакомить вас с инструментом 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-файлов и создание архивных резервных копий.