Отказоустойчивый PostgreSQL кластер. Часть 5. Тестирование. Ansible. Вместо послесловия.


Часть 1. Введение.
Часть 2. Репликация. Repmgr.
Часть 3. Auto-failover. Демоны repmgr.
Часть 4. Высокая доступность. Бэкапирование. Демоны repmgr. Barman.
Часть 5. Тестирование. Ansible. Вместо послесловия.

Ручное переключение серверов

На сервере backup запустите.

su - postgres
repmgr standby switchover -f /etc/repmgrd_db2.conf --log-to-file

Автоматическое переключение серверов

db2 теперь новый мастер. Погасите db2.

shutdown -h now

Подождите пока db1 не станет новым мастером. Запускайте на сервере backup:

tail -50 /var/log/syslog | grep repmgr
repmgrd[6872]: unable to ping "host=10.8.2.1 user=repmgr dbname=repmgr connect_timeout=2"
repmgrd[6872]: unable to connect to upstream node "db2" (node ID: 2)
repmgrd[6872]: checking state of node 2, 1 of 6 attempts
repmgrd[6872]: unable to ping "user=repmgr connect_timeout=2 dbname=repmgr host=10.8.2.1 fallback_application_name=repmgr"
repmgrd[6872]: sleeping 10 seconds until next reconnection attempt
repmgrd[6872]: checking state of node 2, 2 of 6 attempts
repmgrd[6872]: unable to ping "user=repmgr connect_timeout=2 dbname=repmgr host=10.8.2.1 fallback_application_name=repmgr"
repmgrd[6872]: sleeping 10 seconds until next reconnection attempt
repmgrd[6872]: checking state of node 2, 3 of 6 attempts
repmgrd[6872]: unable to ping "user=repmgr connect_timeout=2 dbname=repmgr host=10.8.2.1 fallback_application_name=repmgr"
repmgrd[6872]: sleeping 10 seconds until next reconnection attempt
repmgrd[6872]: checking state of node 2, 4 of 6 attempts
repmgrd[6872]: unable to ping "user=repmgr connect_timeout=2 dbname=repmgr host=10.8.2.1 fallback_application_name=repmgr"
repmgrd[6872]: sleeping 10 seconds until next reconnection attempt
repmgrd[6872]: checking state of node 2, 5 of 6 attempts
repmgrd[6872]: unable to ping "user=repmgr connect_timeout=2 dbname=repmgr host=10.8.2.1 fallback_application_name=repmgr"
repmgrd[6872]: sleeping 10 seconds until next reconnection attempt
repmgrd[6872]: checking state of node 2, 6 of 6 attempts
repmgrd[6872]: unable to ping "user=repmgr connect_timeout=2 dbname=repmgr host=10.8.2.1 fallback_application_name=repmgr"
repmgrd[6872]: unable to reconnect to node 2 after 6 attempts
repmgrd[6872]: primary and this node have the same location ("default")
repmgrd[6872]: no other sibling nodes - we win by default
repmgrd[6872]: this node is the only available candidate and will now promote itself
repmgrd[6872]: promote_command is:#012  "ssh postgres@10.8.1.1 /usr/bin/repmgr standby promote -f /etc/repmgr.conf --log-to-file"
repmgrd[6872]: executing notification command for event "repmgrd_failover_promote"
repmgrd[6872]: 0 followers to notify
repmgrd[6872]: switching to primary monitoring mode
repmgrd[6872]: executing notification command for event "repmgrd_reload"
repmgrd[6872]: monitoring cluster primary "db1" (node ID: 1)

Проверьте кластер.

su - postgres
repmgr -f /etc/repmgrd_db1.conf cluster show

Возврат экс-мастера назад в кластер

db1 снова мастер. Вернем db2 назад в кластер.

Для начала, запустите db2.
Затем, запустите OpenVPN.

systemctl start openvpn

Потом, запустите rejoin на сервере db2.

su - postgres
repmgr -f /etc/repmgr.conf node rejoin -d "postgres://repmgr@10.8.1.1:5432/repmgr" --force-rewind

Repmgr будет использовать pg_rewind, так что возврат сервера в строй должен быть быстрее, чем при полном бэкапировании.

ВАЖНО. Убедитесь, что демоны repmgr переподключились к свежевозвращенному серверу каждый раз когда хотите опять деградировать кластер.

tail -50 /var/log/syslog | grep repmgr
repmgrd[10061]: monitoring primary node "db2" (node ID: 2) in normal state
repmgrd[10061]: attempting to reconnect to node "db2" (ID: 2)
repmgrd[10061]: reconnected to node "db2" (ID: 2)
repmgrd[10061]: node is now a standby, switching to standby monitoring
repmgrd[10061]: executing notification command for event "repmgrd_standby_reconnect"

Возврат поврежденного экс-мастера назад в кластер

ОК, давайте представим, что файлы базы данных на сервере db2 повреждены, но ОС продолжает работать. Процесс восстановления в таком случае очень похож на процесс создания резервного сервера.
Запустите OpenVPN.

systemctl start openvpn

Запустите клонирование и перерегистрацию резервного сервера.

su - postgres
rm -r /var/lib/postgresql/11/main/* #not remove, but move if you need to
repmgr -h 10.8.1.1 -U repmgr -d repmgr -f /etc/repmgr.conf standby clone -F
chmod 700 /var/lib/postgresql/11/main/
sudo pg_ctlcluster 11 main start
repmgr standby register --force

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

Проверяем бэкап

Сымитируйте нагрузку на БД. Зайдите в базу как repmgr на сервере backup.

su - postgres
psql -U repmgr -d repmgr -h 10.8.3.1 -p 54322

Создайте тестовую таблицу и запустите тестовый скрипт.

create table t(n integer);

DO
$
begin 
	for i in 1..100000 loop 
		insert into t values(i); 
		RAISE NOTICE 'Val: %',i; 
		commit; 
	end loop; 
end;
$;

Сразу после этого, жестко перезагрузите сервер db1.

Подождите пока сервер db2 не станет мастером, как было показано выше.

Зайдите на новый мастер(db2) и вставьте еще строчку данных.

psql -U repmgr -d repmgr -h 10.8.3.1 -p 54322
insert into t values (0);

Остановите тестовый экземпляр БД на сервере backup перед разворачиванием бэкапа.

systemctl stop postgresql

Подготовьте директорию PostgreSQL для barman.

rm -r /var/lib/postgresql/11/main/*
chown barman:barman /var/lib/postgresql/11/main/

Восстановите последний возможный бэкап. Barman пока что не поддерживает ключевое слово latest в качестве target-time, поэтому просто укажите дату где-нибудь в будущем, мы переопределим её вскоре.

barman recover main_backup --target-time="2030-01-01 00:00:00" latest /var/lib/postgresql/11/main/

Скопируйте последний имеющийся partial WAL и переименуйте его.

cp /var/lib/barman/main_backup/streaming/*.partial /var/lib/postgresql/11/main/pg_wal/
rename 's/.partial//' /var/lib/postgresql/11/main/pg_wal/*

Переопределите точку восстановления, автоматически заданную barman.

echo "recovery_target_timeline = 'latest'" >> /var/lib/postgresql/11/main/recovery.conf

Верните права назад юзеру postgres и запустите экземпляр.

chown -R postgres:postgres /var/lib/postgresql/11/main/
systemctl start postgresql

Успешный старт базы командой не означает, что она уже восстановлена на последнюю точку. Проверяйте логи, пока база не будет готова принимать rw-соединения.

tail -50 /var/log/postgresql/postgresql-11-main.log
...
[31625] LOG:  restored log file "0000000D000000000000002B" from archive
[31625] LOG:  restored log file "0000000E000000000000002C" from archive
...
[31624] LOG:  database system is ready to accept connections

Зайдите в psql и проверьте что все строки на месте.

su - postgres
psql -U repmgr -d repmgr -h 127.0.0.1
select count(*) from t;

I want to ride my Ansible! Ansible!


ЗДЕСЬ

Вместо послесловия

Так, и что мне дальше делать?

  • Установите HAproxy, чтобы иметь отдельный порт для ro-соединений. Перенаправьте ro-запросы к резервному серверу с автопереключением на мастер, если резервный недоступен. Вы можете использовать external check script и селект к repmgr через порт 54322 чтобы определить роль сервера.
  • Запустите pgbouncer через порт 54322
  • Подумайте дважды о безопасности сервера backup. Это наиболее уязвимый сервер кластера, потому что на нем располагаются все бэкапы и он может подключаться к серверам БД без пароля по ssh.
  • Подумайте дважды о безопасности серверов db1 и db2. Если вы используете barman как метод восстановления в repmgr, серверы БД могут подключаться к backup без пароля по ssh.
  • Установите систему мониторинга, которая будет мониторить демонов repmgr, barman и состояние кластера после автоматического переключения.
  • Поблагодарите меня. Это было нелегко.

15 комментариев к “Отказоустойчивый PostgreSQL кластер. Часть 5. Тестирование. Ansible. Вместо послесловия.”

  1. Большое спасибо за отличную статью!
    Подскажите пожалуйста, когда выполняю ручное переключение мастера с db1 на db2, db2 становится новым мастером, но db1 не становится слейвом.
    На db1 не может стартовать кластер main.
    В логах db1 вижу информацию, что идет восстановление файлов журнала, к примеру последний 00000006.history восстановлен успешно, а следующий 00000007.history (которого еще нет на самом backup сервер) очевидно не восстанавливается.
    Ошибка в логах:
    ERROR: WAL file ‘00000007.history’ not found in server ‘main_backup’ (SSH host: 192.168.6.188)
    ERROR: Remote ‘barman get-wal’ command has failed!
    Если отключить восстановление из бэкапа barman, а тянуть состояние с нового мастера то ошибок нет…

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

  2. а как вы мониторите постгресс если не секрет?
    Я использую обычно postgres_exporter для прометея, вот этот
    https://github.com/wrouesnel/postgres_exporter, однако ему требуется shared_preload_libraries = ‘pg_stat_statements’, но
    в случае с repmgr shared_preload_libraries = ‘repmgr’ и он не работает.

    1. Парметр shared_preload_libraries умеет принимать несколько либ через запятую.

       shared_preload_libraries = 'repmgr, pg_stat_statements'
      
  3. Добрый день.
    repmgr standby switchover -f /etc/repmgrd_db2.conf —log-to-file
    Чет в это пункте он мне ругается.
    ERROR: ownership error for file «/var/lib/postgresql/11/main/recovery.conf»
    DETAIL: file owner is «root», data directory owner is «postgres»
    где я что мог упустит везде с правами норм тем боле на recovery.conf во всех нодах postgres стоит. А на самих нодах переключение выполняется на ура. в чем мож быть проблема?

    1. И всё же попрошу вывод ls -l /var/lib/postgresql/11/main/recovery.conf, чтобы было понятно наверняка 🙂

      1. postgres@pgdbslave:~/11/main$ ls -la /var/lib/postgresql/11/main/recovery.conf
        -rw——- 1 postgres postgres 147 Aug 12 11:17 /var/lib/postgresql/11/main/recovery.conf

        1. Интересно.
          А если вручную зайти под пользователем postgres и попробовать открыть файл, то всё в порядке и он открывается, верно?
          Если да, то какого-то решения в голову больше не приходит.

          1. Да все открывается без проблем под пользователем postgres.

  4. Hi.
    Thank you for your excellent work and documentation.
    I just want to clarify one thing that i tried to get from this howto and i could not.
    You said that this can work without any HAproxy setup on the client side because, if i understood correctly, all the queries are routed through the backup server to the correct dbX server.
    But.. what happen if the backup server dies?

    1. You understand it right. Backup server is the main entry point for such cluster configuration. So, if it dies, all you can do is to manually reconfigure app to use primary postgres instance. The question is it acceptable to do so if you have no backups.

    1. Здравствуйте.
      Использование OpenVPN опционально и отсылает к первой статье цикла.
      В тестах оно носит роль восстановления сетевой связности, т.к. тестирование было на несвязанных локальной сетью машинах.
      Если у вас машины в одной сети, то инструкции для OpenVPN можно (скорее всего) проигнорировать.

Добавить комментарий для Андрей Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *