Часть 1. Введение.
Часть 2. Репликация. Repmgr.
Часть 3. Auto-failover. Демоны repmgr.
Часть 4. Высокая доступность. Бэкапирование. Демоны repmgr. Barman.
Часть 5. Тестирование. Ansible. Вместо послесловия.
В этой части мы:
- сделаем PostgreSQL высоко доступным, используя демоны repmgr
- применим barman для потокового бэкапирования
- используем высокую доступность и barman вместе чтобы хранить бэкапы мастера и резервного сервера вместе, чтобы сэкономить место на диске
По умолчанию, barman может бэкапировать данные с мастера и резервного сервера параллельно, храня бэкапы в разных местах на диске, а не в одном. Это единственное решение при асинхронной репликации. Если мастер упадет, резервный сервер останется с неактуальными данными, часть данных будет потеряна.
При синхронной репликации мы можем продолжить получение WAL с нового мастера. Это означает, что мы можем хранить бэкапы в одном месте, экономя дисковое пространство. Чтобы сделать это прозрачно, мы воспользуемся фичей высокой доступности.
Демоны repmgr
Для начала сделаем кластер высокодоступным. Мы использем события демонов repmgr чтобы поймать переключения серверов кластера. Правила iptables помогут нам перенаправить траффик barman и сервера приложений с портов 54321 и 54322 соответственно на мастер.
Создайте скрипт с кастомными цепочками iptables на сервере backup./usr/local/bin/repmgr_iptables_chains.sh
#!/bin/bash /sbin/sysctl -w net.ipv4.ip_forward=1 /sbin/iptables -t nat -N repmgr_dnat /sbin/iptables -t nat -A OUTPUT -j repmgr_dnat /sbin/iptables -t nat -A PREROUTING -j repmgr_dnat /sbin/iptables -t nat -N repmgr_snat /sbin/iptables -t nat -A POSTROUTING -j repmgr_snat if [[ -f /usr/local/bin/repmgr_master ]]; then master=$(cat /usr/local/bin/repmgr_master) /usr/bin/sudo -u postgres /usr/local/bin/repmgr_handler.sh $master standby_promote fi
Убедитесь, что скрипт будет запущен при каждой загрузке сервера.
crontab -e @reboot /usr/local/bin/repmgr_iptables_chains.sh
Создайте скрипт-помощник. Демоны будут вызывать его при каждом переключении резервного сервера на режим мастера, что сделает наш кластер высокодоступным./usr/local/bin/repmgr_iptables.sh
#!/bin/bash readonly DB="$1" readonly BACKUP="$2" readonly PG_PORT="$3" readonly IN_PORT="$4" if [ -z "$5" ]; then iptables -t nat --flush repmgr_dnat iptables -t nat --flush repmgr_snat iptables -t nat -A repmgr_snat -p tcp -d $DB --dport $PG_PORT -j SNAT --to-source $BACKUP fi iptables -t nat -A repmgr_dnat -p tcp -d $BACKUP --dport $IN_PORT -j DNAT --to-destination $DB:$PG_PORT
Создайте скрипт-обработчик событий демонов./usr/local/bin/repmgr_handler.sh
#!/bin/bash readonly DB1="10.8.1.1" readonly DB2="10.8.2.1" readonly BACKUP="10.8.3.1" readonly SLOT_NAME="barman" readonly BARMAN_NAME="main_backup" readonly PG_PORT="5432" readonly BARMAN_PORT="54321" readonly MASTER_PORT="54322" readonly NODE_ID="$1" EVENT="$2" if [[ "$NODE_ID" == "1" ]]; then IP="$DB1" else IP="$DB2" fi if [[ "$EVENT" =~ ^(primary_register|standby_promote|repmgrd_failover_promote)$ ]]; then sudo /usr/local/bin/repmgr_iptables.sh $IP $BACKUP $PG_PORT $BARMAN_PORT echo "$NODE_ID" > /usr/local/bin/repmgr_master psql -h $IP -p $PG_PORT -U repmgr -d repmgr -c "select pg_create_physical_replication_slot('$SLOT_NAME') where not exists(select 1 from pg_replication_slots where slot_name = '$SLOT_NAME');" sudo -u barman barman receive-wal --stop $BARMAN_NAME 2>/dev/null sudo -u barman barman switch-wal --force --archive --archive-timeout=90 $BARMAN_NAME sudo /usr/local/bin/repmgr_iptables.sh $IP $BACKUP $PG_PORT $MASTER_PORT "app" fi if [[ "$EVENT" =~ ^(standby_register|standby_follow|repmgrd_failover_follow|repmgrd_standby_reconnect)$ ]]; then psql -h $IP -p $PG_PORT -U repmgr -d repmgr -c "select pg_drop_replication_slot('$SLOT_NAME') from pg_replication_slots where slot_name = '$SLOT_NAME';" fi
Посмторим на два интересных момента в скрипте.
#1. Следуя классическому сценарию бэкапирования barman, вам нужно два слота реплицации — один на мастере, другой на резервном сервере. В нашем же случае, мы должны удалить слот с каждого экс-мастера и создать слот на новом мастере после переключения серверов. Если мы оставим слот репликации на экс-мастере, то он будет разростаться пока не забьет всю память сервера БД, потому что в нем будут храниться WAL ожидающие бэкапирования.
#2. Прежде чем открыть порт для соединений от сервера приложений используя скрипт repmgr_iptables.sh, мы принудительно переключаем WAL на новый и архивируем его. Так мы сбрасываем состояние barman и убеждаемся, что ни один WAL не пропущен пока barman не сбросится сам по себе.
Добавьте права на выполнение всем файлам.
chmod +x /usr/local/bin/repmgr_iptables_chains.sh chmod +x /usr/local/bin/repmgr_iptables.sh chmod +x /usr/local/bin/repmgr_handler.sh
Разрешите демонам запускать barman и скрипт-помощник без пароля./etc/sudoers.d/pg_sudoers
postgres ALL = (barman) NOPASSWD: /usr/bin/barman postgres ALL = NOPASSWD: /usr/local/bin/repmgr_iptables.sh
Добавьте следующую строку в конфиги repmgr./etc/repmgrd_db1.conf
/etc/repmgrd_db2.conf
event_notification_command='/usr/local/bin/repmgr_handler.sh %n %e'
Перезапустите демоны.
systemctl restart repmgrd_db1 systemctl restart repmgrd_db2
Откройте порты для barman и сервера приложений вручную.
/usr/local/bin/repmgr_iptables_chains.sh /usr/local/bin/repmgr_iptables.sh 10.8.1.1 10.8.3.1 5432 54321 /usr/local/bin/repmgr_iptables.sh 10.8.1.1 10.8.3.1 5432 54322 "app"
Добавьте id мастера в файл.
echo 1 > /usr/local/bin/repmgr_master chown postgres:postgres /usr/local/bin/repmgr_master
Проверьте подключение к обоим портам.
su - postgres psql -U repmgr -d repmgr -h 10.8.3.1 -p 54321 psql -U repmgr -d repmgr -h 10.8.3.1 -p 54322
Barman
Теперь barman.
Создайте пользователей БД barman на сервере db1.
su - postgres createuser -s barman psql -c "alter user barman with password 'ast84kd';" createuser --replication streaming_barman psql -c "alter user streaming_barman with password 'nxs62jk';"
Создайте файл pgpass для пользователя ОС barman на сервере backup.
su - barman echo "*:*:*:barman:ast84kd" > ~/.pgpass echo "*:*:*:streaming_barman:nxs62jk" >> ~/.pgpass chmod 600 ~/.pgpass
Добавьте следующие строки в начало файла pg_hba.conf на серверах db1 и db2/etc/postgresql/11/main/pg_hba.conf
local replication streaming_barman md5 host replication streaming_barman 127.0.0.1/32 md5 host replication streaming_barman 10.8.3.1/32 md5 local postgres barman md5 host postgres barman 127.0.0.1/32 md5 host postgres barman 10.8.3.1/32 md5
Сделаем процесс репликации синхронным.
Добавьте следующие строки в файл postgresql.conf на сервере db1./etc/postgresql/11/main/postgresql.conf
synchronous_commit = on synchronous_standby_names = 'FIRST 1 (db2, barman_receive_wal)'
И следующие строки в файл postgresql.conf на сервере db2./etc/postgresql/11/main/postgresql.conf
synchronous_commit = on synchronous_standby_names = 'FIRST 1 (db1, barman_receive_wal)'
Применяя параметр «FIRST 1» мы указываем серверу на то, что процесс репликации должен быть синхронным только с одним сервером. Сервер БД имеет приоритет №1.
Если один сервер упадет, кластер продолжит работу синхронно с сервером бэкапов.
Перезапустите PostgreSQL на серверах db1 и db2 чтобы применить изменения.
systemctl restart postgresql
Отредактируйте глобальный конфиг barman на сервере backup./etc/barman.conf
[barman] barman_user = barman configuration_files_directory = /etc/barman.d barman_home = /var/lib/barman log_file = /var/log/barman/barman.log log_level = INFO compression = pygzip ; сжимать WAL, сжатие основного бэкапа не реализовано в barman backup_options = concurrent_backup ; использовать новеший(9.6+) конкурентный бэкап recovery_options = 'get-wal' ; восстанавливать сервер, используя WAL с сервера barman, запрашивая их утилитами get-wal или barman-wal-restore, а не копируя их классически сразу в директорию pg_wal minimum_redundancy = 2 ; всегда хранить как минимум 2 полных бэкапа retention_policy = RECOVERY WINDOW OF 2 WEEKS ; хранить бэкапы как минимум две недели
Создайте конфигурацию бэкапирования нашего кластера./etc/barman.d/main_backup.conf
[main_backup] description = "Main backup" conninfo = host=10.8.3.1 port=54321 user=barman dbname=postgres backup_method = postgres streaming_conninfo = host=10.8.3.1 port=54321 user=streaming_barman streaming_archiver = on slot_name = barman ;streaming_archiver_name = barman_receive_wal
Проверьте подключение к пользователям БД barman.
su - barman psql -c 'SELECT version()' -U barman -h 10.8.1.1 postgres psql -U streaming_barman -h 10.8.1.1 -c "IDENTIFY_SYSTEM" replication=1
Создайте две задачи в cron.
crontab -e * * * * * /usr/bin/barman cron 0 2 * * 1 /usr/bin/barman backup main_backup
barman cron — выполняется каждую минуту, удаляет старые бэкапы, запускает архивацию WAL, и т.д.
barman backup main_backup — выполняется каждый понедельник в 2 часа ночи, выполняет базовый бэкап.
Чтобы выполнять потоковое бэкапирование, barman использует слот реплицирования. Создайте один, если он еще не создан. Затем, запустите barman cron вручную чтобы начать архивирование WAL. Принудительно переключите WAL. Проверьте, что barman работает как нужно. Создайте 2 первых полных бэкапа согласно параметру minimum_redundancy.
barman receive-wal --create-slot main_backup barman cron barman switch-wal --force --archive main_backup barman check main_backup barman backup main_backup barman backup main_backup
(опционально) Можно настроить repmgr так, чтобы он использовал barman для клонирования и восстановления. Это поможет нам восстанавливать БД не обращаясь к мастеру. Добавьте следующие строки в файл repmgr.conf на серверах db1 и db2./etc/repmgr.conf
barman_host=barman@10.8.3.1 barman_server=main_backup restore_command=/usr/bin/barman-wal-restore -U barman 10.8.3.1 main_backup %f %p
На сервере db1 запустите:
su - postgres ssh-keygen -b 2048 -t rsa -N "" -C "postgres@10.8.1.1" ssh-copy-id barman@10.8.3.1
На сервере db2 запустите:
su - postgres ssh-keygen -b 2048 -t rsa -N "" -C "postgres@10.8.2.1" ssh-copy-id barman@10.8.3.1
Теперь мы готовы к тестированию кластера.