Перейти к содержимому

22 Занятие 22: Отказоустойчивые решения / Кластер BiHA

Исходная страница в нативном Markdown: Отказоустойчивые решения / Кластер BiHA
Примечание

Эта страница извлечена из официального PDF в нативный Markdown. Текст слайдов, код и комментарии сохранены в порядке чтения; исходные PDF и HTML остаются эталоном макета. HTML source: pgpro_22_biha.html Archive: PGPRO-handouts-16.zip Страниц PDF: 35

Page 1: Отказоустойчивые решения / Кластер BiHA

Авторские права

© Postgres Professional, 2023–2026 Авторы: Алексей Береснев, Илья Баштанов, Павел Толмачев, Игорь Гнатюк Фото: Олег Бартунов (монастырь Пху и пик Бхрикути, Непал)

Использование материалов курса

Некоммерческое использование материалов курса (презентации, демонстрации) разрешается без ограничений. Коммерческое использование возможно только с письменного разрешения компании Postgres Professional. Запрещается внесение изменений в материалы курса.

Обратная связь

Отзывы, замечания и предложения направляйте по адресу: edu@postgrespro.ru

Отказ от ответственности

Компания Postgres Professional не несет никакой ответственности за любые повреждения и убытки, включая потерю дохода, нанесенные прямым или непрямым, специальным или случайным использованием материалов курса. Компания Postgres Professional не предоставляет каких-либо гарантий на материалы курса. Материалы курса предоставляются на основе принципа «как есть» и компания Postgres Professional не обязана предоставлять сопровождение, поддержку, обновления, расширения и изменения.

Page 2: Темы

  • Кластер BiHA
  • Архитектура и принцип работы
  • Конфигурация
  • Создание кластера
  • Режимы репликации
  • Отработка отказов
  • Выборы
  • Режим 2+1

Page 3: Кластер BiHA

Кластер физической репликации

  • синхронная и асинхронная репликация
  • масштабируемость по операциям чтения
  • Встроенная высокая доступность
    • автоматическое обнаружение и отработка отказа узла
    • кворум на базе алгоритма консенсуса Raft
    • не требует внешнего управления кластером
  • Работает на Linux-платформах

Комментарии преподавателя

Расширение BiHA (Built-in High Availability) позволяет организовать отказоустойчивый кластер физической репликации, включающий в себя выделенный узел-лидер и несколько узлов-последователей. Лидер передает потоки репликации на узлы-последователи, доступные только для чтения. Репликация может быть синхронной или асинхронной. Балансировка запросов на чтение между несколькими узлами позволяет увеличить пропускную способность системы.

Клиентские соединения могут направляться на определенные узлы внешним балансировщиком или пулером. В версии Postgres Pro Enterprise 17 для этого используют расширение Proxima.

https://postgrespro.ru/docs/enterprise/17/proxima#PROXIMA

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

BiHA не использует внешнее программное обеспечения для управления кластером. https://postgrespro.ru/docs/enterprise/16/biha

В настоящее время BiHA не работает в среде MS Windows.

Page 4: Архитектура

Source slide page 4: Архитектура{#source-figure-004 caption=“Source slide page 4: Архитектура”}

Комментарии преподавателя

Расширение BiHA включает в себя доработанное ядро СУБД, SQL-интерфейс управления и сам код расширения.

На каждом из узлов запускаются служебные процессы BiHA worker, координирующие работу кластера. Эти процессы обмениваются служебной информацией, используя BiHA Control Protocol (BCP). Сами данные с узла-лидера передаются на последователи с помощью штатного механизма физической репликации (поток WAL-записей).

Для инициализации кластера и управления им используется утилита bihactl. Она может создавать узел-лидер, добавлять узлы-последователи, преобразовывать уже существующий экземпляр в узел-лидер или узел-последователь в кластере, а также проверять статус узлов кластера.

https://postgrespro.ru/docs/enterprise/16/biha-architecture#BIHA-ARCHITE CTURE

Page 5: Параметры конфигурации

Source slide page 5: Параметры конфигурации{#source-figure-005 caption=“Source slide page 5: Параметры конфигурации”}

biha.nquorum = 3 biha.minnodes = 3

Комментарии преподавателя

При создании узлов кластера с помощью утилиты bihactl, кроме очевидных параметров (адрес, порт, каталог данных) нужно указать параметры, относящиеся ко всему кластеру. Самые важные из них:

● biha.nquorum — минимальное число узлов, при котором проводятся выборы лидера;

● biha.minnodes — минимальное число узлов, при котором лидер изменяет данные.

Если biha.nquorum или более связанных узлов остались без лидера, они проводят выборы нового лидера. Поведение текущего лидера от этого параметра не зависит.

Если лидер находится в группе из не менее чем biha.minnodes узлов, он обрабатывает запросы на чтение и запись, а при меньшем числе узлов — только на чтение.

По умолчанию для biha.minnodes берется значение biha.nquorum. Чтобы избежать ситуации split-brain, оба параметра рекомендуется задать как (общее число узлов + 1) / 2, округленное в большую сторону. Тогда при разделении сети лидер, оказавшись в меньшинстве, перестанет принимать запросы на запись, а большинство узлов выберет нового лидера. Однако при четном числе узлов имеет смысл задать biha.minnodes как ровно половину от общего числа узлов, чтобы разделение на две равные части не повлияло на работу лидера.

https://postgrespro.ru/docs/enterprise/16/biha-architecture#BIHA-CLUSTER-VARIANTS

Page 6: Инициализация кластера

Source slide page 6: Инициализация кластера{#source-figure-006 caption=“Source slide page 6: Инициализация кластера”}

Комментарии преподавателя

Кластер BiHA можно получить из существующей системы, использующей физическую репликацию, но мы создадим новый трехузловой кластер с нуля.

Первый узел будущего кластера необходимо инициализировать командой bihactl init. Будет создан экземпляр со служебной базой данных biha_db и схемой biha, для него будут установлены необходимые конфигурационные параметры, а также создан слот репликации.

Поскольку мы рассчитываем на три узла, параметр biha.nquorum установим равным двум (параметр biha.minnodes получит то же значение).

https://postgrespro.ru/docs/enterprise/16/biha-architecture#BIHA-POSTGRE S-CONFIGURATION

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

Далее мы будем встречаться с понятием номера поколения кластера (term). Текущее состояние соответствует нулевому поколению, в него входит единственный узел. Номер поколения автоматически увеличивается при изменении состояния кластера, например, при удалении или добавлении узла, при смене лидера.

Page 7: Подготовка BiHA-кластера

В этой демонстрации основной экземпляр PostgresPro Enterprise не используется, остановим его.

student$ sudo systemctl stop postgrespro-ent-16.service

Все узлы будут локальными экземплярами. Подготовим каталог для данных узла-лидера:

postgres$ mkdir /var/lib/pgpro/ent-16-biha-1

Подключаться к узлам по протоколу репликации будет пользователь biha_replication_user; его пароли на всех узлах кластера BiHA должны быть одинаковыми. В нашем случае удобно включить в файл паролей одну общую строку:

postgres$ echo '*:*:*:biha_replication_user:biha' >> ~/.pgpass
postgres$ chmod 600 ~/.pgpass

С помощью команды init утилиты bihactl инициализируем кластер и создадим в нем узел-лидер. Будет запущена утилита initdb, а также сформирована конфигурация:

postgres$ bihactl init \
  --biha-node-id=1 \
  --host=host1 \
  --port=7001 --pgdata=/var/lib/pgpro/ent-16-biha-1 \
  --biha-port=7101 \
  --nquorum=2 \
  > /var/lib/postgresql/magic_str
bihactl: password for biha_replication_user was taken from pgpass
initdb: --icu-locale not specified, using lc_collate
initdb: warning: enabling "trust" authentication for local connections
initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

С помощью параметров утилиты заданы: –biha-node-id — уникальный идентификатор узла кластера; –host, –port и –pgdata — узел, порт и путь к каталогу данных создаваемого экземпляра; –biha-port — порт для обмена служебной информацией между узлами; –nquorum — значение параметра biha.nquorum для всех узлов. Команда init возвращает «магическую» строку, которая содержит данные для подключения последователей к лидеру. Строку удобно использовать в скриптах подготовки узлов-последователей, чтобы не вводить данные вручную, поэтому мы записали ее в файл /var/lib/postgresql/magic_str:

/var/lib/postgresql/magic_str
dmVyc2lvbj0xIGhvc3Q9aG9zdDEgcG9ydD03MDAxIGJpaGEtcG9ydD03MTAx

Фактически, в этой строке зашифрован набор параметров:

postgres$ cat /var/lib/postgresql/magic_str | base64 -d
version=1 host=host1 port=7001 biha-port=7101

Запустим узел.

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-1 \
  -l /var/lib/pgpro/ent-16-biha-1/pgpro-ent.log \
  start
waiting for server to start.... done
server started
student$ psql -p 7001 -h host1 -U postgres -d biha_db

Конфигурационные параметры при инициализации были записаны в дополнительные файлы, подключаемые к файлам postgresql.conf и pg_hba.conf с помощью директив include. Параметры настройки узла размещаются в подключенном файле postgresql.biha.conf:

=> SELECT name, setting
FROM pg_file_settings
WHERE sourcefile ~ 'postgresql.biha.conf';

Page 8: Page 8

           name            |   setting
---------------------------+-------------
 synchronous_standby_names |
 wal_level                 | replica
 hot_standby               | on
 max_wal_senders           | 10
 max_replication_slots     | 11
 max_slot_wal_keep_size    | 5GB
 wal_keep_size             | 1GB
 biha.id                   | 1
 application_name          | biha_node_1
 biha.port                 | 7101
 biha.host                 | host1
 port                      | 7001
 biha.nquorum              | 2
 biha.minnodes             | 2
 listen_addresses          | *
 biha.use_ssl              | 0
 primary_slot_name         | biha_node_1
(17 rows)

Параметры кластера должны быть согласованы на всех узлах, поэтому для их изменения используются специальные функции, которые следует запускать только на лидере. Настройки аутентификации находятся в подключенном файле pg_hba.biha.conf:

=> SELECT type, database, user_name, address, auth_method
FROM pg_hba_file_rules
WHERE file_name ~ 'pg_hba.biha.conf';
 type |   database    |        user_name        | address |  auth_method
------+---------------+-------------------------+---------+---------------
 host | {postgres}    | {biha_replication_user} | all     | scram-sha-256
 host | {biha_db}     | {biha_replication_user} | all     | scram-sha-256
 host | {replication} | {biha_replication_user} | all     | scram-sha-256
(3 rows)

Ряд параметров, критически важных для работы расширения, хранится в отдельном файле pg_biha/biha.conf, и их нельзя изменить с помощью команды ALTER SYSTEM:

/var/lib/pgpro/ent-16-biha-1/pg_biha/biha.conf
primary_conninfo=
synchronous_standby_names=
node_count=1
1:host1:7101:7001:regular
crc=2740808754

Кроме этого, в параметре shared_preload_libraries основного файла конфигурации указывается загружаемая библиотека расширения:

=> SELECT name, setting
FROM pg_file_settings
WHERE name = 'shared_preload_libraries' AND sourcefile ~ 'postgresql.conf';
           name           | setting
--------------------------+---------
 shared_preload_libraries | biha
(1 row)

Состояние узла сохраняется в файле biha.state:

/var/lib/pgpro/ent-16-biha-1/pg_biha/biha.state
node_id=1
term=0
leader_id=1
rewind_state=0
waltrim_state=0
waltrim_common_tli=0
waltrim_start_lsn=0
waltrim_end_lsn=0
node_error=0
next_tli=0
next_tle_begin=0
next_tle_end=0
cur_tli=0

Page 9: Page 9

cur_tle_begin=0
cur_tle_end=0
crc=1733808887

А состояние всего кластера можно увидеть с помощью команды bihactl status:

postgres$ bihactl status --host=host1 --port=7001
 id | leader_id | term | online |   state   | last_known_state | since_last_hb
----+-----------+------+--------+-----------+------------------+---------------
  1 |         1 |    0 | t      | LEADER_RO | LEADER_RO        |
(1 row)

Состояние LEADER_RO означает, что узел находится в режиме только для чтения. При значении biha.minnodes=1 кластер состоял бы из единственного узла со статусом RW. Ту же информацию можно получить, обратившись к представлению biha.status_v.

Page 10: Добавление узла

Source slide page 10: Добавление узла{#source-figure-010 caption=“Source slide page 10: Добавление узла”}

Комментарии преподавателя

Новый узел добавляется в кластер командой bihactl add, выполняемой на подключаемом узле; при этом в кластере будет сформировано новое поколение. Когда число узлов станет равным значению параметра biha.minnodes, кластер станет полностью работоспособным: его лидер сможет работать на запись.

Перед созданием кластера необходимо обеспечить сетевую связность и настроить на всех узлах синхронизацию времени.

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

При biha.nquorum = 2 и biha.minnodes = 2 потеря любого узла приведет к недоступности кластера на запись.

Если установить biha.nquorum = 1 и biha.minnodes = 1, при разделении сети между двумя работоспособными узлами последователь станет лидером — возникнет ситуация split-brain с двумя работающими лидерами. Это самая плохая ситуация.

Если же установить biha.nquorum = 2 и biha.minnodes = 1, то отказ последователя не нарушит работу лидера, и при разделении сети split-brain не возникнет. Но при отказе лидера последователь не станет новым лидером.

Page 11: Два узла

Добавим в кластер узел-последователь. Используем магическую строку, полученную при инициализации кластера. Будет создана физическая резервная копия узла-лидера (по умолчанию с помощью pg_basebackup):

postgres$ bihactl add \
  --biha-node-id=2 \
  --host=host2 \
  --port=7002 --pgdata=/var/lib/pgpro/ent-16-biha-2 \
  --biha-port=7102 \
  --magic-string=dmVyc2lvbj0xIGhvc3Q9aG9zdDEgcG9ydD03MDAxIGJpaGEtcG9ydD03MTAx

Запускаем новый узел и ждем, пока он подключится к лидеру.

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-2 \
  -l /var/lib/pgpro/ent-16-biha-2/pgpro-ent.log \
  start
waiting for server to start............. done
server started
=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    1 | t      | LEADER_RW | LEADER_RW        |
  2 |         1 |    1 | t      | FOLLOWER  | FOLLOWER         | 00:00:01.280459
(2 rows)

Теперь кластер состоит из двух узлов. Первый из них является лидером и может теперь принимать запросы на изменение данных (LEADER_RW), а второй является последователем (FOLLOWER). Посмотрим на процессы экземпляров. Среди них есть BiHA worker, координирующие работу кластера, и обычные для физической репликации процессы.

student$ ps -o pid,command --ppid 860058  # лидер
    PID COMMAND
 860059 postgres: BiHA worker: node 1
 860061 postgres: checkpointer
 860062 postgres: background writer
 860063 postgres: cfs-worker-0
 860106 postgres: postgres biha_db 127.0.0.1(59700) idle
 861275 postgres: walwriter
 861276 postgres: autovacuum launcher
 861277 postgres: logical replication launcher
 861306 postgres: walsender biha_replication_user 127.0.0.1(59068) streaming 0/16A22E8
student$ ps -o pid,command --ppid 860879  # последователь
    PID COMMAND
 860880 postgres: BiHA worker: node 2
 860881 postgres: startup recovering 000000020000000000000001
 860882 postgres: checkpointer
 860883 postgres: background writer
 860885 postgres: cfs-worker-0
 861305 postgres: walreceiver streaming 0/16A22E8

Page 12: Три узла

Source slide page 12: Три узла{#source-figure-012 caption=“Source slide page 12: Три узла”}

Комментарии преподавателя

Добавляя дополнительные узлы в кластер, мы избавляемся от недостатка двухузловой конфигурации: в ней невозможно продолжить запись после потери сетевой связности без риска split-brain. Трех узлов уже достаточно для того, чтобы кластер оставался полностью работоспособным после одного любого сбоя.

В такой конфигурации один из узлов является лидером, остальные — последователями. При отказе лидера новый будет автоматически избран на основе кворума. Лидер также может быть назначен вручную.

Page 13: Три узла в кластере

Добавим в кластер еще один узел-последователь:

postgres$ bihactl add \
  --biha-node-id=3 \
  --host=host3 \
  --port=7003 --pgdata=/var/lib/pgpro/ent-16-biha-3 \
  --biha-port=7103 \
  --magic-string=dmVyc2lvbj0xIGhvc3Q9aG9zdDEgcG9ydD03MDAxIGJpaGEtcG9ydD03MTAx

Запустим третий узел и проверим статус кластера:

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-3 \
  -l /var/lib/pgpro/ent-16-biha-3/pgpro-ent.log \
  start
waiting for server to start............. done
server started
=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    2 | t      | LEADER_RW | LEADER_RW        |
  2 |         1 |    2 | t      | FOLLOWER  | FOLLOWER         | 00:00:01.008276
  3 |         1 |    2 | t      | FOLLOWER  | FOLLOWER         | 00:00:01.008276
(3 rows)

Появился еще один последователь, номер поколения увеличился. Состояние подключения узлов в кластере можно получить из представления nodes_v:

=> SELECT * FROM biha.nodes_v;
 id | host  | port | state  | since_conn_start | conn_count
----+-------+------+--------+------------------+------------
  1 | host1 | 7101 |        |                  |
  2 | host2 | 7102 | ACTIVE | 00:00:55.127388  |          1
  3 | host3 | 7103 | ACTIVE | 00:00:17.127388  |          1
(3 rows)

Проверим репликацию. Создадим базу на лидере, а в ней — таблицу:

=> CREATE DATABASE pgpro_biha;
CREATE DATABASE
=> \c pgpro_biha
You are now connected to database "pgpro_biha" as user "postgres".
=> CREATE TABLE test AS SELECT 'Проверка репликации' msg;
SELECT 1

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

student$ psql -p 7002 -h host2 -U postgres
=> \c pgpro_biha
You are now connected to database "pgpro_biha" as user "postgres".

Данные появились на втором узле:

=> SELECT * FROM test;
         msg
---------------------
 Проверка репликации
(1 row)

И на третьем:

student$ psql -p 7003 -h host3 -U postgres

Page 14: Page 14

=> \c pgpro_biha
You are now connected to database "pgpro_biha" as user "postgres".
=> SELECT * FROM test;
         msg
---------------------
 Проверка репликации
(1 row)

Page 15: Режимы репликации

Source slide page 15: Режимы репликации{#source-figure-015 caption=“Source slide page 15: Режимы репликации”}

synchronous_standby_names = ANY N MIN M (biha_node1, biha_node2, …)

Комментарии преподавателя

По умолчанию кластер BiHA использует асинхронную репликацию, но можно использовать и синхронную кворумную — задав ее при инициализации кластера или перейдя на нее в существующем кластере.

Синхронизацией управляет параметр synchronous_standby_names: при фиксации транзакции лидер будет ожидать подтверждения от любых N (ANY N) узлов из списка синхронных. Синхронный режим включается функцией biha.set_sync_standbys, которая и устанавливает число N.

Если временно доступно менее N синхронных узлов, фиксация транзакций будет приостановлена. Чтобы продолжить работу в случае временной недоступности синхронных узлов, можно включить нестрогую кворумную синхронную репликацию. Тогда лидер будет продолжать подтверждать транзакции, пока к нему подключено как минимум M синхронных узлов (MIN M). Значение устанавливается функцией biha.set_sync_standbys_min, а значение −1 возвращает кластер к строгой синхронной репликации.

После включения синхронной репликации перейти на асинхронную уже нельзя, но можно изменить список синхронных узлов функциями biha.set_ssn, biha.remove_from_ssn и biha.add_to_ssn. Узлы, не входящие в список, будут работать асинхронно.

https://postgrespro.ru/docs/enterprise/16/biha-administration#BIHA-ENABLI NG-SYNC-REPLICATION

https://postgrespro.ru/docs/enterprise/16/runtime-config-replication#GUC-SY NCHRONOUS-STANDBY-NAMES

Page 16: Синхронная репликация

Включим в кластере синхронную кворумную репликацию с подтверждением от двух узлов:

=> \c biha_db
You are now connected to database "biha_db" as user "postgres".
=> SELECT biha.set_sync_standbys(2);
 set_sync_standbys
-------------------
 t
(1 row)

Для просмотра текущего значения параметра synchronous_standby_names используем функцию biha.get_ssn:

=> SELECT * FROM biha.get_ssn();
                   get_ssn
----------------------------------------------
 ANY 2 (biha_node_1,biha_node_2,biha_node_3 )
(1 row)

Page 17: Отказ последователя

Source slide page 17: Отказ последователя{#source-figure-017 caption=“Source slide page 17: Отказ последователя”}

Комментарии преподавателя

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

Если же используется синхронная репликация, то при настройке synchronous_standby_names = ANY 2 отказ узла приведет к невозможности завершения транзакции: лидер должен дождаться подтверждения от двух узлов-последователей, а работает только один.

Чтобы продолжить работу в такой ситуации, можно включить нестрогую синхронную репликацию ANY 2 MIN 1.

Page 18: Отказ синхронного последователя

Нарушим кворум синхронизации, остановив второй узел:

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-2 \
  stop
waiting for server to shut down........ done
server stopped

Кластер пока считает узел работающим. Подождем, пока будет обнаружен отказ…

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    3 | t      | LEADER_RW | LEADER_RW        |
  2 |         1 |    2 | f      | UNKNOWN   | FOLLOWER         | 00:00:21.846679
  3 |         1 |    3 | t      | FOLLOWER  | FOLLOWER         | 00:00:00.846679
(3 rows)

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

=> CREATE DATABASE new_db;

Смягчим ограничение, включив нестрогую кворумную синхронную репликацию:

postgres$ psql -p 7001 -d biha_db -c 'SELECT biha.set_sync_standbys_min(1)'
 set_sync_standbys_min
-----------------------
 t
(1 row)

Теперь транзакция завершена:

CREATE DATABASE

В параметре synchronous_standby_names появилось указание MIN со значением 1:

=> SELECT * FROM biha.get_ssn();
                      get_ssn
----------------------------------------------------
 ANY 2 MIN 1 (biha_node_1,biha_node_2,biha_node_3 )
(1 row)

Page 19: Отказ последователей

Source slide page 19: Отказ последователей{#source-figure-019 caption=“Source slide page 19: Отказ последователей”}

Комментарии преподавателя

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

Page 20: Отказ последователей

Сейчас один из последователей остановлен, но кластер в рабочем состоянии:

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    4 | t      | LEADER_RW | LEADER_RW        |
  2 |         1 |    2 | f      | UNKNOWN   | FOLLOWER         | 00:00:22.742462
  3 |         1 |    3 | t      | FOLLOWER  | FOLLOWER         | 00:00:01.742462
(3 rows)

Остановим оставшегося последователя:

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-3 \
  stop
waiting for server to shut down.... done
server stopped

И немного подождем, чтобы кластер отработал отказ узла…

=> \c biha_db
You are now connected to database "biha_db" as user "postgres".

В строю остался лидер, но доступен он лишь для чтения:

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state | since_last_hb
----+-----------+------+--------+-----------+------------------+---------------
  1 |         1 |    4 | t      | LEADER_RO | LEADER_RO        |
  2 |         1 |    4 | f      | UNKNOWN   | UNKNOWN          |
  3 |         1 |    4 | f      | UNKNOWN   | UNKNOWN          |
(3 rows)

Снова запустим второй узел и дождемся его возвращения в строй.

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-2 \
  -l /var/lib/pgpro/ent-16-biha-2/pgpro-ent.log \
  start
waiting for server to start.... done
server started
student$ psql -p 7002 -h host2 -U postgres -d biha_db

Статус лидера сменился на LEADER_RW, кластер обрабатывает запросы на изменение данных:

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    4 | t      | LEADER_RW | LEADER_RW        |
  2 |         1 |    4 | t      | FOLLOWER  | FOLLOWER         | 00:00:01.187268
  3 |         1 |    4 | f      | UNKNOWN   | UNKNOWN          |
(3 rows)

Page 21: Отказ лидера

Source slide page 21: Отказ лидера{#source-figure-021 caption=“Source slide page 21: Отказ лидера”}

Комментарии преподавателя

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

Применяемый в выборах алгоритм консенсуса RAFT гарантирует однозначное определение нового лидера. Выборы проводятся в группах узлов, составляющих кворум; чтобы предотвратить ситуацию split-brain, значение параметра biha.nquorum должно превышать половину узлов.

В процессе выборов узлы выдвигают себя в качестве кандидатов на роль лидера и запрашивают голоса других узлов. Фактор победы в голосовании — наличие на узле наиболее актуальных данных, то есть новым лидером кластера становится последователь с наибольшим числом записей в WAL. В синхронном кластере можно задать для узлов приоритет, определяющий порядок выдвижения на роль лидера: для этого в параметре biha.node_priority узла указывается тайм-аут, по истечении которого узел предложит себя в качестве кандидата.

При необходимости можно вообще запретить узлу становиться лидером или участвовать в голосовании — для этого существуют параметры biha.can_be_leader и biha.can_vote.

https://postgrespro.ru/docs/enterprise/16/biha-architecture#BIHA-ELECTION S

Page 22: Новый лидер

Source slide page 22: Новый лидер{#source-figure-022 caption=“Source slide page 22: Новый лидер”}

Комментарии преподавателя

Помимо автоматического переключения узлов, BiHA поддерживает ручное переключение. Вручную назначить нового лидера можно с помощью функции biha.set_leader; ее рекомендуется вызывать на том узле, который планируется сделать лидером.

https://postgrespro.ru/docs/enterprise/16/biha-administration#BIHA-SWITCH OVER

При изменении состояния кластера есть возможность вызывать на узлах заранее зарегистрированные пользовательские функции — обработчики событий. Это функции для обратного вызова (callback-функции), которые могут выполнить дополнительные действия, например, отправить оповещение администратору, уведомить об изменениях внешнее ПО, управляющее подключением клиентов (различные прокси и балансировщики), или обеспечить ограждение (fencing) старого лидера.

https://postgrespro.ru/docs/enterprise/16/biha-administration#BIHA-CALLBA CKS

Page 23: Возвращение узла

Source slide page 23: Возвращение узла{#source-figure-023 caption=“Source slide page 23: Возвращение узла”}

Комментарии преподавателя

После переключения ролей узлов BiHA выполняет синхронизацию данных кластера в изменившейся конфигурации. Чаще всего на последователях требуется применение записей WAL, полученных с нового лидера. Однако в случае, когда в состав кластера возвращается старый лидер, может потребоваться обратное действие — его «откат» до состояния нового, который выполняется утилитой pg_rewind.

Автоматическое выполнение отката определяется параметром biha.autorewind и по умолчанию выключено. Так сделано потому, что существует риск потери пользовательских транзакций в журнале предзаписи на синхронизируемом узле. Кроме этого, при неудачной автоматической синхронизации узел может перейти в состояние ошибки, и для возвращения его в строй потребуется вмешательство администратора.

https://postgrespro.ru/docs/enterprise/16/biha-administration#BIHA-AUTOM ATIC-CLUSTER-SYNCHRONIZATION-AFTER-FAILOVER

Page 24: Отказ лидера

Сейчас в кластере два узла:

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    4 | t      | LEADER_RW | LEADER_RW        |
  2 |         1 |    4 | t      | FOLLOWER  | FOLLOWER         | 00:00:01.322084
  3 |         1 |    4 | f      | UNKNOWN   | UNKNOWN          |
(3 rows)

Теперь остановим лидера.

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-1 \
  stop
waiting for server to shut down.......... done
server stopped
=> \c biha_db
You are now connected to database "biha_db" as user "postgres".

После небольшого ожидания посмотрим на втором узле, в каком состоянии находится кластер…

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |  state   | last_known_state |  since_last_hb
----+-----------+------+--------+----------+------------------+-----------------
  1 |         1 |    4 | f      | UNKNOWN  | LEADER_RO        | 00:00:11.846925
  2 |         1 |    4 | t      | FOLLOWER | FOLLOWER         |
  3 |         1 |    3 | f      | UNKNOWN  | UNKNOWN          |
(3 rows)

Последний работающий узел кластера остался в состоянии FOLLOWER. Он он может стать лидером, поскольку для кворума нужны два узла. Принудительно назначим лидера:

=> SELECT biha.set_leader(2);
 set_leader
------------
 t
(1 row)

Новый лидер принадлежит уже новому поколению. При этом запросы на изменение данных он выполнять не может:

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    4 | f      | UNKNOWN   | UNKNOWN          | 00:00:12.790722
  2 |         2 |    5 | t      | LEADER_RO | LEADER_RO        |
  3 |         1 |    3 | f      | UNKNOWN   | UNKNOWN          |
(3 rows)

Снова включим первый узел.

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-1 \
  -l /var/lib/pgpro/ent-16-biha-1/pgpro-ent.log \
  start
waiting for server to start.... done
server started
student$ psql -p 7001 -h host1 -U postgres -d biha_db

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

Page 25: Page 25

Таким образом, узлы поменялись ролями.

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         2 |    5 | t      | FOLLOWER  | FOLLOWER         | 00:00:00.573122
  2 |         2 |    5 | t      | LEADER_RW | LEADER_RW        |
  3 |         1 |    3 | f      | UNKNOWN   | UNKNOWN          |
(3 rows)

Вернем в строй и третий узел, запретив ему становиться лидером:

/var/lib/pgpro/ent-16-biha-3/postgresql.auto.conf
biha.can_be_leader = false
postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-3 \
  -l /var/lib/pgpro/ent-16-biha-3/pgpro-ent.log \
  start
waiting for server to start.... done
server started

В кластере снова три узла. Лидером по-прежнему выступает второй узел, все узлы находятся в одном новом поколении:

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         2 |    5 | t      | FOLLOWER  | FOLLOWER         | 00:00:00.374409
  2 |         2 |    5 | t      | LEADER_RW | LEADER_RW        |
  3 |         2 |    5 | t      | FOLLOWER  | FOLLOWER         | 00:00:01.374409
(3 rows)

Если теперь остановить второй узел (лидера), то оставшиеся узлы автоматически выберут нового лидера из своего числа:

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-2 \
  stop
waiting for server to shut down.......... done
server stopped
student$ psql -p 7003 -h host3 -U postgres -d biha_db

Немного подождем…

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    4 | t      | LEADER_RO | LEADER_RO        | 00:00:00.692224
  2 |         2 |    5 | f      | UNKNOWN   | UNKNOWN          | 00:00:22.692224
  3 |         1 |    6 | t      | FOLLOWER  | FOLLOWER         |
(3 rows)

Лидером снова стал первый узел; третий мы запретили выбирать.

Page 26: Режим 2+1

Source slide page 26: Режим 2+1{#source-figure-026 caption=“Source slide page 26: Режим 2+1”}

Комментарии преподавателя

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

Режим работы узла-рефери определяется параметром –mode команды bihactl add. Поддерживаются два режима:

● referee. Узел только принимает участие в выборах лидера, в синхронной репликации не участвует.

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

В обоих режимах узел-рефери отправляет и получает сообщения о контроле состояния по каналу управления и поддерживает функции мониторинга кластера.

Рефери — это конечное состояние узла: он не может стать ни лидером, ни последователем.

https://postgrespro.ru/docs/enterprise/16/biha-architecture#BIHA-REFEREE

Page 27: Режим 2+1. Узел-рефери

Взамен остановленного нами второго узла создадим узел-рефери. Но сначала удалим второй узел из кластера. Сделать это можно с помощью функции biha.remove_node, вызывать которую нужно на лидере:

student$ psql -p 7001 -h host1 -U postgres -d biha_db
=> SELECT biha.remove_node(2);
 remove_node
-------------
 t
(1 row)

В кластере осталось два узла:

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    7 | t      | LEADER_RW | LEADER_RW        |
  3 |         1 |    7 | t      | FOLLOWER  | FOLLOWER         | 00:00:00.245768
(2 rows)

При добавлении узла-рефери (параметр –mode=referee) утилита pg_basebackup создаст частичную резервную копию лидера кластера. Данные нового экземпляра будут размещены в каталоге данных остановленного узла, поэтому этот каталог следует заранее очистить:

postgres$ rm -rf /var/lib/pgpro/ent-16-biha-2
postgres$ bihactl add \
  --biha-node-id=2 \
  --host=host2 \
  --port=7002 --pgdata=/var/lib/pgpro/ent-16-biha-2 \
  --biha-port=7102 \
  --mode=referee \
  --use-leader "host=host1 port=7001 biha-port=7101"

Стартуем вновь созданный экземпляр:

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-2 \
  -l /var/lib/pgpro/ent-16-biha-2/pgpro-ent.log \
  start
waiting for server to start........... done
server started

На новый экземпляр была скопирована только база biha_db и системные таблицы. Пользовательские данные других баз (даже postgres) не переносятся, чтобы уменьшить потребление ресурсов. Если все-таки необходимо, чтобы база postgres попала на узел-рефери (она может понадобится некоторым утилитам или системам мониторинга), нужно в команде выше дополнительно указать параметр –referee-with-postgres-db.

student$ psql -p 7002 -h host2 -U postgres -d biha_db
=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    8 | t      | LEADER_RW | LEADER_RW        | 00:00:00.500849
  2 |         1 |    8 | t      | REFEREE   | REFEREE          |
  3 |         1 |    8 | t      | FOLLOWER  | FOLLOWER         | 00:00:01.500849
(3 rows)

Остановим лидера.

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-1 \
  stop
waiting for server to shut down.... done
server stopped

Оставшиеся узлы должны автоматически выбрать нового. Узел-рефери участвует в голосовании, но сам стать лидером

Page 28: Page 28

Source slide page 28: Page 28{#source-figure-028 caption=“Source slide page 28: Page 28”}

никогда не сможет.

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |  state   | last_known_state | since_last_hb
----+-----------+------+--------+----------+------------------+----------------
  1 |         1 |    8 | f      | UNKNOWN  | LEADER_RW        | 00:00:11.19196
  2 |         1 |    8 | t      | REFEREE  | REFEREE          |
  3 |         1 |    8 | t      | FOLLOWER | FOLLOWER         | 00:00:00.19196
(3 rows)

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

=> ALTER SYSTEM RESET biha.can_be_leader;
ALTER SYSTEM
=> SELECT pg_reload_conf();
 pg_reload_conf
----------------
 t
(1 row)
=> \dconfig biha.can_be_leader
List of configuration parameters
     Parameter      | Value
--------------------+-------
 biha.can_be_leader | on
(1 row)

Теперь третий узел стал лидером:

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    8 | f      | UNKNOWN   | UNKNOWN          | 00:00:23.938969
  2 |         3 |    9 | t      | REFEREE   | REFEREE          | 00:00:00.938969
  3 |         3 |    9 | t      | LEADER_RW | LEADER_RW        |
(3 rows)

Page 29: Итоги

Postgres Pro BiHA — кластерное решение для высокой доступности на основе физической репликации

  • Не требует установки дополнительного ПО
  • Автоматически переключает и восстанавливает узлы при сбоях
  • Допускает гибкую настройку для достижения баланса производительности, надежности и стоимости системы

Page 30: Практика

  1. Настройте синхронную физическую репликацию между двумя серверами. 2. Преобразуйте ведущий узел в лидера синхронного трехузлового BiHA-кластера. Проверьте его статус. 3. Преобразуйте ведомый узел (реплику) в узел-последователь и проверьте статус кластера. 4. Добавьте в кластер еще один узел-последователь, работающий как асинхронная реплика. Проверьте статус кластера и работу репликации. Остановите этот узел и убедитесь в том, что это не мешает фиксации транзакций.

Комментарии преподавателя

  1. Создайте два дополнительных экземпляра Postgres Pro Enterprise: для ведущего выполните инициализацию с помощью initdb, а ведомый создайте из копии ведущего, созданной pg_basebackup.

  2. Используйте команду bihactl init c параметрами –convert и –sync-standbys=1.

  3. Для добавления последователя используйте команду bihactl add c параметрами –convert-standby и –use-leader.

  4. Для добавления последователя используйте команду bihactl add c параметрами –convert-standby и –use-leader, а затем переведите его в асинхронный режим функцией biha.remove_from_ssn.

Page 31: 1. Синхронная репликация

Подготовим экземпляр Postgres Pro, который станет ведущим. Создаем каталог PGDATA:

postgres$ mkdir /var/lib/pgpro/ent-16-biha-1

Инициализируем экземпляр:

postgres$ /opt/pgpro/ent-16/bin/initdb \
  -U postgres \
  -k \
  -D /var/lib/pgpro/ent-16-biha-1
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.
initdb: --icu-locale not specified, using lc_collate
Using language tag "en-US" for ICU locale "en_US.UTF-8".
The database cluster will be initialized with this locale configuration:
  provider:    icu
  ICU locale:  en-US
  LC_COLLATE:  en_US.UTF-8
  LC_CTYPE:    en_US.UTF-8
  LC_MESSAGES: en_US.UTF-8
  LC_MONETARY: ru_RU.UTF-8
  LC_NUMERIC:  ru_RU.UTF-8
  LC_TIME:     ru_RU.UTF-8
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".
Data page checksums are enabled.
fixing permissions on existing directory /var/lib/pgpro/ent-16-biha-1 ... ok
creating subdirectories ... ok
selecting dynamic shared memory implementation ... posix
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default time zone ... Europe/Moscow
creating configuration files ... ok
performing automatic tuning ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok
initdb: warning: enabling "trust" authentication for local connections
initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.
Success. You can now start the database server using:
    /opt/pgpro/ent-16/bin/pg_ctl -D /var/lib/pgpro/ent-16-biha-1 -l logfile start

Дополним конфигурацию узла 1:

postgres$ echo include_dir \'conf.d\' >> /var/lib/pgpro/ent-16-biha-1/postgresql.conf
postgres$ mkdir /var/lib/pgpro/ent-16-biha-1/conf.d
/var/lib/pgpro/ent-16-biha-1/conf.d/syncro.conf
cluster_name = 'syncro_primary'
port = 7001

Запускаем:

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-1 \
  -l /var/lib/pgpro/ent-16-biha-1/pgpro-ent.log \
  start
waiting for server to start.... done
server started

Разворачиваем реплику. Сделаем копию ведущего узла, разместив ее в каталоге /var/lib/pgpro/ent-16-biha-2

Page 32: Page 32

postgres$ /opt/pgpro/ent-16/bin/pg_basebackup \
  -p 7001 --pgdata=/var/lib/pgpro/ent-16-biha-2 \
  -U postgres \
  -R \
  --checkpoint=fast

Дополним конфигурацию узла 2:

/var/lib/pgpro/ent-16-biha-2/conf.d/syncro.conf
cluster_name = 'syncro_standby'
port = 7002

Запускаем:

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-2 \
  -l /var/lib/pgpro/ent-16-biha-2/pgpro-ent.log \
  start
waiting for server to start........... done
server started

Проверим статус репликации:

student$ psql -p 7001 -h host1 -U postgres
=> SELECT state, application_name, sync_state FROM pg_stat_replication;
   state   | application_name | sync_state
-----------+------------------+------------
 streaming | syncro_standby   | async
(1 row)

Настроим синхронную репликацию. Для этого установим на ведущем сервере значение параметра synchronous_standby_names:

=> ALTER SYSTEM SET synchronous_standby_names = 'syncro_standby';
ALTER SYSTEM
=> SELECT pg_reload_conf();
 pg_reload_conf
----------------
 t
(1 row)

Репликация стала синхронной:

=> SELECT state, application_name, sync_state FROM pg_stat_replication;
   state   | application_name | sync_state
-----------+------------------+------------
 streaming | syncro_standby   | sync
(1 row)

2. Преобразование ведущего в узел-лидер BiHA

Остановим ведущий сервер.

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-1 \
  stop
waiting for server to shut down.... done
server stopped

Как и в демонстрации, зададим пароль для роли biha_replication_user, записав его в файл:

postgres$ echo '*:*:*:biha_replication_user:biha' >> ~/.pgpass
postgres$ chmod 600 ~/.pgpass

Команда bihactl init с параметром –convert преобразует узел в лидера BiHA-кластера. Мы хотим продолжить работу в синхронном режиме, поэтому в параметре –sync-standbys зададим число синхронных узлов-последователей для подключения к лидеру:

Page 33: Page 33

postgres$ bihactl init \
  --biha-node-id=1 \
  --host=host1 \
  --port=7001 --pgdata=/var/lib/pgpro/ent-16-biha-1 \
  --biha-port=7101 \
  --convert \
  --sync-standbys=1 \
  --nquorum=2
bihactl: password for biha_replication_user was taken from pgpass
bihactl: leader started with 'pg_proaudit, biha'
dmVyc2lvbj0xIGhvc3Q9aG9zdDEgcG9ydD03MDAxIGJpaGEtcG9ydD03MTAx

Запускаем лидера, проверяем статус кластера:

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-1 \
  -l /var/lib/pgpro/ent-16-biha-1/pgpro-ent.log \
  start
waiting for server to start.... done
server started
student$ psql -p 7001 -h host1 -U postgres -d biha_db
=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state | since_last_hb
----+-----------+------+--------+-----------+------------------+---------------
  1 |         1 |    0 | t      | LEADER_RO | LEADER_RO        |
(1 row)

По умолчанию значение biha.minnodes устанавливается равным biha.nquorum (у нас это 2), поэтому новый лидер не может пока выполнять изменение данных.

3. Преобразование ведомого сервера в последователя BiHA

Остановим ведомый сервер.

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-2 \
  stop
waiting for server to shut down........ done
server stopped

Нужно, чтобы пароль роли biha_replication_user в файле паролей совпадал с паролем этой роли на лидере. В нашем случае это так, и команда bihactl init с параметром –convert-standby преобразует узел в последователя BiHA-кластера:

postgres$ bihactl add \
  --biha-node-id=2 \
  --host=host2 \
  --port=7002 --pgdata=/var/lib/pgpro/ent-16-biha-2 \
  --biha-port=7102 \
  --convert-standby \
  --use-leader 'host=host1 port=7001 biha-port=7101'

Запускаем последователя, с лидера проверяем статус кластера:

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-2 \
  -l /var/lib/pgpro/ent-16-biha-2/pgpro-ent.log \
  start
waiting for server to start.... done
server started
=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    1 | t      | LEADER_RW | LEADER_RW        |
  2 |         1 |    1 | t      | FOLLOWER  | FOLLOWER         | 00:00:00.710236
(2 rows)

4. Асинхронный последователь

Page 34: Page 34

Добавим второго последователя:

postgres$ bihactl add \
  --biha-node-id=3 \
  --host=host3 \
  --port=7003 --pgdata=/var/lib/pgpro/ent-16-biha-3 \
  --biha-port=7103 \
  --use-leader 'host=host1 port=7001 biha-port=7101'
postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-3 \
  -l /var/lib/pgpro/ent-16-biha-3/pgpro-ent.log \
  start
waiting for server to start............. done
server started

Новый узел подключится как синхронный. Переведем его в асинхронный режим репликации:

=> SELECT * FROM biha.remove_from_ssn(3);
 remove_from_ssn
-----------------
 t
(1 row)
=> SELECT * FROM biha.get_ssn();
             get_ssn
---------------------------------
 ANY 1 (biha_node_1,biha_node_2)
(1 row)

Проверим статус кластера:

=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    3 | t      | LEADER_RW | LEADER_RW        |
  2 |         1 |    3 | t      | FOLLOWER  | FOLLOWER         | 00:00:00.910271
  3 |         1 |    3 | t      | FOLLOWER  | FOLLOWER         | 00:00:00.910271
(3 rows)

Проверим работу репликации:

=> CREATE DATABASE pgpro_biha;
CREATE DATABASE
student$ psql -p 7002 -h host2 -U postgres
=> \c pgpro_biha
You are now connected to database "pgpro_biha" as user "postgres".
student$ psql -p 7003 -h host3 -U postgres
=> \c pgpro_biha
You are now connected to database "pgpro_biha" as user "postgres".

Репликация работает в разных режимах:

=> SELECT state, application_name, sync_state FROM pg_stat_replication;
   state   | application_name | sync_state
-----------+------------------+------------
 streaming | biha_node_2      | quorum
 streaming | biha_node_3      | async
(2 rows)

Теперь отключим третий узел:

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-3 \
  stop
waiting for server to shut down.... done

Page 35: Page 35

server stopped
=> SELECT * FROM biha.status_v;
 id | leader_id | term | online |   state   | last_known_state |  since_last_hb
----+-----------+------+--------+-----------+------------------+-----------------
  1 |         1 |    3 | t      | LEADER_RW | LEADER_RW        |
  2 |         1 |    3 | t      | FOLLOWER  | FOLLOWER         | 00:00:00.888897
  3 |         1 |    3 | f      | UNKNOWN   | FOLLOWER         | 00:00:21.888897
(3 rows)

Поскольку узел использовал асинхронную репликацию, вывод его из строя не мешает фиксации транзакций:

=> CREATE TABLE t ();
CREATE TABLE

Уборка

Остановим и удалим экземпляры кластера BiHA.

postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-1 \
  stop
waiting for server to shut down........ done
server stopped
postgres$ /opt/pgpro/ent-16/bin/pg_ctl \
  -w \
  -D /var/lib/pgpro/ent-16-biha-2 \
  stop
waiting for server to shut down........ done
server stopped
student$ sudo rm -rf /var/lib/pgpro/ent-16-biha-1 /var/lib/pgpro/ent-16-biha-2 /var/lib/pgpro/ent-16-
biha-3