Как я упоминал ранее, для реализации высокой доступности MFA сервиса буду поднимать несколько экземпляров PrivacyIdea серверов. PrivacyIdea все свое состояние хранит в субд. И для решение всей задачи, мне достаточно обеспечить высокую доступность на уровне баз. В документации к сервису предлагается два решения:
- Использование централизированной менеджмент системы СУБД (Например: Mariadb Galera, Pgpool);
- Использование два инстанса MySQL в режиме master-master.
Разумеется в моем случаи целесобразнее будет использование второго варианта. Вообщем я взялся за изучения вопроса эсплуатации master-to-master субд. И мнения у большинства - нигативные, из основных притензий к такому подходу, это нарватся на рассихронизацию данных в обоих бд. Также при вставке уникального значения столбца в обе базы, приведет к вылету инстансов или к прерыванию репликации. Выход из подобных ситуаций это создание active/passive кластера. Мы добавляем выше какой либо балансировщик (keepalived, например) и пишем данные в одну мастер ноду вторая же нода используется как горячий бекап. В случаи падения первого мастера, мы продолжаем писать уже во второй мастер.
Опять же, если говорить про целесобразность схемы. Стоит учитывать специфику сервиса, будь это финансовый или платежный сервис, то такого городить я бы не стал. В нашем случаи, допускается просадки по консистенстности, но важна доступность.
Данная схема закрывает вопрос этот вопрос, имхо.
Установка MariaDB
Для начала на оба инстанса проинсталируем пакеты с MariaDB:
[All servers]# yum install mariadb mariadb-server mariadb-devel
Запускаем оба инстанса, и инициализируем сценарий настройки безопасности:
[All servers]# systemctl enable --now mariadb
[All servers]# mysql_secure_installation
Открываем порт, для межсетевого взаимодействия двух нод:
[All servers]# firewall-cmd --add-port=3306/tcp --permanent
[All servers]# firewall-cmd --reload
Настройка репликации
На первой мастер ноде отредактируем конфиг - mariadb:
[root@mfa01 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
--
[mysqld]
...
bind-address=*
server-id=1
log_bin=mysql-bin
binlog-format=ROW
В конфиге под контекстом [mysqld]
, добавляем настройки:
bind-address
- с какой адреса принимает подключения инстанс бд.server-id
- уникальный id идентификатор ноды, которая участвует в репликации.log_bin
- в значении этой директивы, указываем куда хотим писать журнал с событиями, в которых описываются изменения базы данных.binlog-format
- указывается тип журналирования, в моей случаи тип строка.
На второй мастер ноде добавляем аналогичные директивы:
[root@mfa02 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
--
[mysqld]
...
bind-address=*
server-id=2
log_bin=mysql-bin
binlog-format=ROW
Из отличий, меняем только id (server-id
) во второй ноде.
На обоих нодах перезапускаем сервис:
[All servers]# systemctl restart mariadb
Подключаемся к базе на первом мастере и создаем пользоваля, который будет использоваться второй нодой для репликации данных.
MariaDB [(none)]> stop slave;
MariaDB [(none)]> grant replication slave on *.* to 'repl'@'%' identified by 'PASSWORD';
MariaDB [(none)]> flush privileges;
Смотрим статус мастера, в этом выводе для нас важны данные поля Position
и File
, Эти значения будут использоваться для последующей конфигурации второго мастера:
MariaDB [(none)]> show master status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 | 655 | | |
+------------------+----------+--------------+------------------+
Откючаемся от базы, и делаем фулл бекап для дальнейшего восставновления на втором мастере:
[root@mfa01 ~]# mysqldump --all-databases -u root -p > master_backup.sql
Этот дайм закидываем на вторую ноду, и восстанавливаем:
[root@mfa02 ~]# mysql -u root -p < master_backup.sql
И перезапускаем инстанс:
[root@mfa02 ~]# systemctl restart mariadb
Подключаемся к базе на второй ноде и поднимаем репликацию, указав второму серверу, где нужно искать файл журнала:
MariaDB [(none)]> stop slave;
MariaDB [(none)]> change master to master_host='192.168.120.44', master_user='repl', master_password='PASS', master_log_file='mysql-bin.000001', master_log_pos=655;
Обратите внимание, что в директивах:
master_host
- указывается ip первого мастераmaster_user/master_password
- логин/пароль пользователя с правами репликации, которого создали ранее.master_log_file
- название журнала (Я просил запомнить)master_log_pos
- номер позиции.
Ну и теперь запускаем слейва:
MariaDB [(none)]> start slave;
Посмотреть статус реплицируемой ноды, можно через команду:
MariaDB [(none)]> show slave status\G;
В выводе этой команды, на данный момент можно обратить внимание на два параметра:
Slave_IO_Running
- поток input/output, соединение с мастер нодой. (Значение - yes, говорит нам об успешности)Slave_SQL_Running
- sql поток с мастером. (Также в значении - yes, говорит об успешности)Slave_SQL_Running_State
- обычно отображается сообщение об текущем состоянии. Сейчас схема работы такая, первая нода в роли мастера, вторая нода как обычная реплика. То есть репликация реализова, как бы в одну сторону. На стороне первой ноды поменяем мастера, что бы репликация работала в двунаправленном режиме. Для этого на стороне второго мастера вызываем команду -show status master
, для получения данных имени лог файла и номера позиции:
MariaDB [(none)]> show master status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000002 | 342 | | |
+------------------+----------+--------------+------------------+
Теперь подключаемся к первому инстансу, и меняем настройки мастера:
MariaDB [(none)]> stop slave;
MariaDB [(none)]> change master to master_host='192.168.120.46', master_user='repl', master_password='PASSWORD', master_log_file='mysql-bin.000002', master_log_pos=342;
MariaDB [(none)]> start slave;
Как вы уже поняли, в значение мастер хоста указан ip второго мастера и имя/позиция журнала тоже от второй ноды.
Тестируем репликацию
На этом с настройкой бд все.
Можем протестировать работу репликацию на двух нодах, путем поочередного создания баз или табличек: Я создал базу на первой ноде, и потчи сразу вывел список баз на второй ноде. Реплика отработала, база отобразилась.
Повторяю действия в обратном порядке: И обратный сценарий тоже отработал корректно.
Настройка виртуального IP
Виртуальный (или плавающий IP) нам нужен для создания единой точки доступа к бекандам. Вообщем на два сервера устанавливаем keepalived:
[All servers]# yum install keepalived -y
Редактируем конфиг сервиса:
[root@mfa01 ~]# cat /etc/keepalived/keepalived.conf
---
global_defs {
enable_script_security
}
vrrp_script database_check {
script "/usr/bin/systemctl is-active mariadb >/dev/null && echo 1 || echo 0"
interval 5
}
vrrp_instance pi-cluster {
state MASTER
interface ens192
virtual_router_id 254
priority 100
advert_int 2
nopreempt
authentication {
auth_type PASS
auth_pass PASSWORD
}
virtual_ipaddress {
192.168.120.45
}
track_script {
postgresql_check
}
}
Конфиг получился достаточно скромный. Из основного, я добавил проверку database_check
доступности базы, с интервалом 5 секунд.
В главном контексте я определяю состояние инстанса (первая нода будем мастером), приоритет ноды и etc.
Конфиг на второй ноде:
global_defs {
enable_script_security
}
vrrp_script database_check {
script "/usr/bin/systemctl is-active mariadb >/dev/null && echo 1 || echo 0"
vrrp_instance pi-cluster {
state BACKUP
interface ens192
virtual_router_id 254
priority 50
advert_int 2
nopreempt
authentication {
auth_type PASS
auth_pass PASSWORD
}
virtual_ipaddress {
192.168.120.45
}
track_script {
postgresql_check
}
}
В конфигурации второй ноды, отличие только в состоянии (тут оно - Backup), и более низком приоритете.
Есть один важный момент, я добавил опцию nopreempt
. Преставим такую ситуацию, что между нодами флапнула сетка и виртуальный ip перетек на второю ноду. Какое-то время прошло и первая нода вновь стала доступна, виртуальный ip откатился обратно. И как бы это нормальное поведение keepalived.
Но проблема в том, что в период недоступности первой ноды, на второй ноде уже накопилась какая-то дельта данных в базе. И при быстром откате на первую ноду, мы теряем данные.
То есть как бы откатываемся на прошлое состояние.
Такой косяк может произойти, когда база имеет уже жирный размер, и жирный лаг в репликации. И нам получается нужно время, что бы донакатить изменения. Выше упомянутая опция решает эту проблему.
Например, первая нода стала недоступная и через период времени восстановилась, keepalived поменяет состояние этой мастер ноды на Backup и виртуальный адрес не откиниться обратно.
Открываем порт на фаере,
[All servers]# firewall-cmd --permanent --add-rich-rule='rule protocol value="vrrp" accept'
success
[All servers]# firewall-cmd --reload
Ну и запускаем сервис:
[All servers]# systemctl enable --now keepalived
Теперь остается только попробовать различные тесткейсы, так сказать пошатать класстер.