Настройка кластера MariaDB Galera на сервере Ubuntu 18.04

12.12.2020

Теги: CLILinuxMySQLUbuntuWeb-разработкаБазаДанныхСервер

Когда проект небольшой, для его работы достаточно одного сервера, на котором расположены все службы: веб-сервер, сервер БД и почтовый сервер. Но когда проект становится большим, может понадобится выделить для БД отдельный сервер или даже несколько серверов. Чтобы поддерживать синхронное состояние БД на всех серверах одновременно — нужно использовать репликацию.

MariaDB Galera — это кластерная система для MariaDB типа master-master. Начиная с MariaDB 10.1 программное обеспечение Galera и MariaDB Server поставляются в одном пакете. На данный момент MariaDB Galera может работать только с движками баз данных InnoDB и XtraDB. Если одна из баз данных дает сбой — она автоматически отключается от кластера.

Минимальный кластер Galera состоит из трех узлов. Рекомендуется запускать кластер с нечетным количеством узлов, чтобы при возникновении проблем с применением транзакции на одном узле (например, из-за проблемы с сетью, или когда машина не отвечает на запросы), два других узла могли создать кворум (т.е. большинство) и продолжить выполнение транзакций.

Установка на первом узле

Устанавливаем mariadb и rsync (понадобится для выполнения синхронизации):

$ sudo apt install mariadb-server rsync -y

Запускаем скрипт безопасности mysql_secure_installation. Сначала будет запрошен пароль root — поскольку пароля еще нет, просто нажимаетм Enter. Потом надо установить пароль для root и ответить на несколько вопросов.

$ sudo mysql_secure_installation

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
password for the root user.  If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none): Enter
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.

Set root password? [Y/n] Y
New password: пароль
Re-enter new password: пароль
Password updated successfully!
Reloading privilege tables..
 ... Success!

By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] Y
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] Y
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] Y
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] Y
 ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

Хотя мы изменили пароль для пользователя root, но подключиться к серверу БД без использования sudo сейчас нельзя. По умолчанию MariaDB использует unix_socket плагин для аутентификации пользователей — изменим это на старый добрый mysql_native_password.

$ sudo mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 30
Server version: 10.1.47-MariaDB-0ubuntu0.18.04.1 Ubuntu 18.04

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

> SELECT user, plugin, host FROM mysql.user;
+------+-------------+-----------+
| user | plugin      | host      |
+------+-------------+-----------+
| root | unix_socket | localhost |
+------+-------------+-----------+
1 row in set (0.00 sec)

> UPDATE mysql.user SET plugin = 'mysql_native_password' WHERE user = 'root';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

> SELECT user, plugin, host FROM mysql.user;
+------+-----------------------+-----------+
| user | plugin                | host      |
+------+-----------------------+-----------+
| root | mysql_native_password | localhost |
+------+-----------------------+-----------+
1 row in set (0.00 sec)

> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

> exit
Bye
Плагин unix_socket (auth_socket в MySQL) проверяет, что пользователь Linux, который подключается к серверу, соответствует пользователю MariaDB. Другими словами, чтобы пользователь somebody мог подключиться к серверу БД — в операционной системе должен существовать пользователь somebody.

Теперь создаем файл конфигурации сервера БД. В принципе, можно поместить все настройки в my.cnf, но лучше будет создать отдельный файл в директории /etc/mysql/conf.d/.

$ sudo nano /etc/mysql/conf.d/galera.cnf
[mysqld]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0
# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
# Galera Cluster Configuration
wsrep_cluster_name="GaleraCluster"
wsrep_cluster_address="gcomm://192.168.110.40,192.168.110.41,192.168.110.42"
# Galera Synchronization Configuration
wsrep_sst_method=rsync
# Galera Node Configuration
wsrep_node_address="192.168.110.40"
wsrep_node_name="ClusterNode1"

Здесь ip-адрес 192.168.110.40 — это ip-адрес первого узла кластера.

Рассмотрим, что означают значения основных параметров:

  • binlog_format — формат лога, в котором будут сохраняться запросы (row — двоичные данные)
  • default-storage-engine — движок SQL таблиц, который мы будем использовать
  • innodb_autoinc_lock_mode — режим работы генератора значений AUTO_INCREMENT
  • bind-address — ip-адрес, на котором программа будет слушать соединения (в нашем случае все ip адреса)
  • wsrep_on — включает репликацию
  • wsrep_provider — библиотека, с помощью которой будет выполняться репликация
  • wsrep_cluster_name — имя кластера, должно быть одинаковым на всех узлах
  • wsrep_cluster_address — список адресов серверов, между которыми будет выполняться репликация
  • wsrep_sst_method — транспорт, который будет использоваться для передачи данных
  • wsrep_node_address — ip-адрес текущего узла репликации
  • wsrep_node_name — имя текущего узла репликации

Установка на втором узле

Устанавливаем mariadb и rsync:

> sudo apt install mariadb-server rsync -y

Запускаем скрипт безопасности

$ sudo mysql_secure_installation

Изменяем способ аутентификации:

$ sudo mysql
> UPDATE mysql.user SET plugin = 'mysql_native_password' WHERE user = 'root';
> FLUSH PRIVILEGES;
> exit

Создаем файл конфигурации:

$ sudo nano /etc/mysql/conf.d/galera.cnf
[mysqld]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0
# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
# Galera Cluster Configuration
wsrep_cluster_name="GaleraCluster"
wsrep_cluster_address="gcomm://192.168.110.40,192.168.110.41,192.168.110.42"
# Galera Synchronization Configuration
wsrep_sst_method=rsync
# Galera Node Configuration
wsrep_node_address="192.168.110.41"
wsrep_node_name="ClusterNode2"

Здесь ip-адрес 192.168.110.41 — это ip-адрес второго узла кластера.

Установка на третьем узле

Устанавливаем mariadb и rsync:

> sudo apt install mariadb-server rsync -y

Запускаем скрипт безопасности

$ sudo mysql_secure_installation

Изменяем способ аутентификации:

$ sudo mysql
> UPDATE mysql.user SET plugin = 'mysql_native_password' WHERE user = 'root';
> FLUSH PRIVILEGES;
> exit

Создаем файл конфигурации:

$ sudo nano /etc/mysql/conf.d/galera.cnf
[mysqld]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0
# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
# Galera Cluster Configuration
wsrep_cluster_name="GaleraCluster"
wsrep_cluster_address="gcomm://192.168.110.40,192.168.110.41,192.168.110.42"
# Galera Synchronization Configuration
wsrep_sst_method=rsync
# Galera Node Configuration
wsrep_node_address="192.168.110.42"
wsrep_node_name="ClusterNode3"

Здесь ip-адрес 192.168.110.42 — это ip-адрес третьего узла кластера.

Настройка фаервола ufw

Остался последний штрих перед запуском — это настройка фаервола ufw. Сначала нужно разрешить доступ к серверу по ssh, в противном случае будет потерян доступ, потому что ufw будет блокировать входящие ssh-соединения.

$ sudo ufw allow OpenSSH

Если фаервол еще не включен — включаем:

$ sudo ufw enable

Открываем порты, которые нужны для работы:

$ sudo ufw allow 3306/tcp
$ sudo ufw allow 4444/tcp
$ sudo ufw allow 4567/tcp
$ sudo ufw allow 4567/udp
$ sudo ufw allow 4568/tcp

Проверяем созданные правила:

$ sudo ufw status verbose
Состояние: активен
Журналирование: on (low)
По умолчанию: deny (входящие), allow (исходящие), disabled (маршрутизированные)
Новые профили: skip

В                          Действие    Из
----------------------------------------------------
22/tcp (OpenSSH)           ALLOW IN    Anywhere
3306/tcp                   ALLOW IN    Anywhere
4444/tcp                   ALLOW IN    Anywhere
4567/tcp                   ALLOW IN    Anywhere
4567/udp                   ALLOW IN    Anywhere
4568/tcp                   ALLOW IN    Anywhere
22/tcp (OpenSSH (v6))      ALLOW IN    Anywhere (v6)
3306/tcp (v6)              ALLOW IN    Anywhere (v6)
4444/tcp (v6)              ALLOW IN    Anywhere (v6)
4567/tcp (v6)              ALLOW IN    Anywhere (v6)
4567/udp (v6)              ALLOW IN    Anywhere (v6)
4568/tcp (v6)              ALLOW IN    Anywhere (v6)

Все эти команды нужно выполнить на всех трех узлах.

Все готово, запускаем

Перед запуском кластера нужно убедиться, что сервис MariaDB остановлен на всех узлах:

$ sudo systemctl stop mariadb.service # первый узел
$ sudo systemctl stop mariadb.service # второй узел
$ sudo systemctl stop mariadb.service # третий узел

Далее запускаем скрипт создания нового кластера на первом узле:

$ sudo galera_new_cluster # первый узел

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

> mysql -uroot -pпароль -e "show status like 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 1     |
+--------------------+-------+

Теперь запускаем сервер БД на втором узле кластера:

$ sudo systemctl start mariadb.service # второй узел

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

$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 2     |
+--------------------+-------+

Теперь запускаем сервер БД на третьем узле кластера:

$ sudo systemctl start mariadb.service # третий узел

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

$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 3     |
+--------------------+-------+

Проверяем, как работает

Чтобы проверить, как работает репликация, создадим БД testing на первом узле и убедимся, что новая БД существует и на втором узле.

$ mysql -uroot -pпароль
Welcome to the MariaDB monitor.
> CREATE DATABASE testing;
Query OK, 1 row affected (0.01 sec)
> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| testing            |
+--------------------+
4 rows in set (0.00 sec)
> exit
Bye

Смотрим наличие БД testing на втором узле:

$ mysql -uroot -pпароль
Welcome to the MariaDB monitor.
> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| testing            |
+--------------------+
4 rows in set (0.00 sec)
> exit
Bye

Проверка работоспособности

Проверить, сколько узлов в кластере:

$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 3     |
+--------------------+-------+

Синхронизирован ли узел с кластером:

$ mysql -uroot -pпароль -e "show status like 'wsrep_local_state_comment'"
+---------------------------+--------+
| Variable_name             | Value  |
+---------------------------+--------+
| wsrep_local_state_comment | Synced |
+---------------------------+--------+

Принадлежит ли узел Primary Component:

$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_status'"
+----------------------+---------+
| Variable_name        | Value   |
+----------------------+---------+
| wsrep_cluster_status | Primary |
+----------------------+---------+

Что такое Primary Component

Primary Component — это набор узлов Galera, которые могут взаимодействовать друг с другом по сети и содержат большинство узлов. Если из-за сетевых проблем узлы оказались разделены на две группы — только одна группа может совершать транзакции — которая оказалась в большинстве. Другая группа не будет совершать транзакции, что исключает возможность того, что две части кластера будут совершать разные транзакции.

В работоспособном кластере все узлы могут обмениваться данными друг с другом, поэтому все они принадлежат Primary Component и могут получать обновления. На любом узле, который находится в Primary Component, переменная состояния wsrep_cluster_size показывает текущее количество узлов в кластере.

$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 5     | кластер из пяти узлов
+--------------------+-------+

Переменная wsrep_cluster_status для каждого узла кластера имеет значение Primary:

$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_status'"
+----------------------+---------+
| Variable_name        | Value   |
+----------------------+---------+
| wsrep_cluster_status | Primary | статус каждого узла
+----------------------+---------+

Если один или несколько узлов отделяются от кластера из-за сетевых проблем, каждый узел в кластере решает, находится ли он на стороне большинства или меньшинства. Это этого зависит их дальнейшее поведение — обрабатывать или отклонять SQL-запросы.

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

$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 2     | два узла в меньшинстве
+--------------------+-------+
$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_status'"
+----------------------+-------------+
| Variable_name        | Value       |
+----------------------+-------------+
| wsrep_cluster_status | non-Primary | статус каждого узла
+----------------------+-------------+

Узлы, которые обнаруживают, что их большинство, остаются в состоянии Primary и продолжают обработку SQL-запросов.

$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 3     | три узла в большинстве
+--------------------+-------+
$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_status'"
+----------------------+---------+
| Variable_name        | Value   |
+----------------------+---------+
| wsrep_cluster_status | Primary | статус каждого узла
+----------------------+---------+

Как только проблемы в сети будут устранены, все узлы, не входящие в Primary Component, которые продолжили работу, синхронизируются с узлами из Primary Component и снова присоединяются к кластеру. Любые узлы, на которых процессы mariadb.service были завершены, необходимо будет перезапустить для повторного присоединения.

Остановка и запуск кластера

Допустим, нам по каким-то причинам надо остановить работу всех трех узлов. Трудно представить себе ситуацию, когда это бы потребовалось, но это позволит лучше понять работу кластера. Но перед остановкой службы mariadb.service посмотрим содержимое файла /var/lib/mysql/grastate.dat на всех трех узлах — оно будет одинаковое:

$ sudo cat /var/lib/mysql/grastate.dat
# GALERA saved state
version: 2.1
uuid:    9885d452-3c5d-11eb-a709-2383d79f0fe4
seqno:   -1
safe_to_bootstrap: 0

Если произойдет авария на одном из узлов (сбой питания) — содержимое этого файла не изменится — именно потому, что все произошло внезапно — и не было времени на то, чтобы в этот файл что-то записать.

Остановим службу на первом узле:

$ sudo systemctl stop mariadb.service # на первом узле
$ sudo cat /var/lib/mysql/grastate.dat # на первом узле
# GALERA saved state
version: 2.1
uuid:    9885d452-3c5d-11eb-a709-2383d79f0fe4
seqno:   5
safe_to_bootstrap: 0

Обратите внимание на значение safe_to_bootstrap — значение ноль означает, что этот узел не подходит для начального запуска кластера. Остальные узлы продолжают работу — обрабатывают SQL-запросы — изменяют состояние базы данных. Значит, у этого узла нет всех данных, чтобы с него начинать запуск кластера — иначе данные будут потеряны.

Два оставшихся узла образуют Primary Component и продолжат обслуживать клиентские запросы. Чтобы вернуть узел в кластер — нужно просто запустить службу mariadb.service.

Остановим службу на втором узле:

$ sudo systemctl stop mariadb.service # на втором узле
$ sudo cat /var/lib/mysql/grastate.dat # на втором узле
# GALERA saved state
version: 2.1
uuid:    9885d452-3c5d-11eb-a709-2383d79f0fe4
seqno:   5
safe_to_bootstrap: 0

Аналогичная ситуация — узел не подходит для начального запуска кластера.

Оставшийся третий узел образует Primary Component и продолжит обслуживать клиентские запросы. Чтобы вернуть первый и второй узлы в кластер — нужно их просто запустить. Однако, когда первый и/или второй узел присоединяется к кластеру, третий узел будет переключен в состояние «Donor/Desynced (Донор)», так как он должен обеспечить передачу состояния.

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

Остановим службу на третьем узле:

$ sudo systemctl stop mariadb.service # на третьем узле
$ sudo cat /var/lib/mysql/grastate.dat # на третьем узле
# GALERA saved state
version: 2.1
uuid:    9885d452-3c5d-11eb-a709-2383d79f0fe4
seqno:   16
safe_to_bootstrap: 1

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

$ sudo galera_new_cluster # на третьем узле
$ sudo systemctl start mariadb.service # на втором узле
$ sudo systemctl start mariadb.service # на первом узле

Восстановление кластера после сбоя

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

Файл /var/lib/mysql/gvwstate.dat создается в момент присоединения узла к кластеру в состоянии Primary Component. В случае неожиданного сбоя этот файл позволит узлу понять состояние кластера до момента сбоя. Если служба останавливается корректно для проведения каких-то работ на сервере — файл удаляется.

$ sudo cat /var/lib/mysql/gvwstate.dat
my_uuid: 2ff4dc71-3e1a-11eb-bfd5-469d3c3f38e8
#vwbeg
view_id: 3 2ff4dc71-3e1a-11eb-bfd5-469d3c3f38e8 23
bootstrap: 0
member: 2ff4dc71-3e1a-11eb-bfd5-469d3c3f38e8 0
member: f5289b65-3de7-11eb-847a-4e353cafe6db 0
member: f59e93d3-3deb-11eb-a76f-4f2c7fbc23ca 0
#vwend

Все, что находится между #vwbeg и #vwend — содержит информацию о кластере в состоянии Primary Component. То, что выделено красным — вместе составляют уникальный идентификатор кластера в состоянии Primary Component. Зеленым выделен уникальный идентификатор этого узла кластера. Дальше идут идентификаторы каждого узла кластера в состоянии Primary Component.

Узлы, перечисленные в файле gvwstate.dat, будут пытаться восстановить Primary Component, как только все участники начнут видеть друг друга. Так что для восстановления работы кластера нам ничего предпринимать не нужно, все восстановится в автоматическом режиме.

1. Восстановление после сбоя на одном узле

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

$ sudo ip link set dev enp0s3 down # на первом узле

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

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

$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 2     |
+--------------------+-------+

На втором узле выполним SELECT-запрос:

$ mysql -uroot -pпароль
Welcome to the MariaDB monitor.
> use testing;
Database changed
> select * from testing;
+----+---------+
| id | name    |
+----+---------+
|  2 | testing |
+----+---------+
1 row in set (0.00 sec)
> exit

На первом узле посмотрим статус — это non-Primary:

$ mysql -uroot -pпароль -e "show status like 'wsrep_cluster_status'"
+----------------------+-------------+
| Variable_name        | Value       |
+----------------------+-------------+
| wsrep_cluster_status | non-Primary |
+----------------------+-------------+

На первом узле выполним SELECT-запрос:

$ mysql -uroot -pпароль
Welcome to the MariaDB monitor.
> use testing;
Database changed
> select * from testing;
ERROR 1047 (08S01): WSREP has not yet prepared node for application use
> exit

Как только первый узел станет доступен — он автоматически присоединяется к кластеру — от нас никаких действий не требуется. Если посмотреть файл gvwstate.dat — то в нем будут три узла — это то состояние кластера, пока мы не вырубили сетевой интерфейс.

$ sudo cat /var/lib/mysql/gvwstate.dat # на первом узле
my_uuid: c9e2b0b4-3ea4-11eb-b8d7-8b86360f78b6
#vwbeg
view_id: 3 c0e9bf47-3ea4-11eb-940b-6fceb3b13836 21
bootstrap: 0
member: c0e9bf47-3ea4-11eb-940b-6fceb3b13836 0
member: c9e2b0b4-3ea4-11eb-b8d7-8b86360f78b6 0
member: d8fb898f-3ea4-11eb-81d7-ab850ffd5b31 0
#vwend

2. Восстановление после сбоя на двух узлах

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

$ sudo ip link set dev enp0s3 down # на втором узле

Два узла недоступны, а оставшийся в одиночестве третий узел не может самостоятельно сформировать кворум — поэтому переключается в non-Primary режим и отказывается выполнять SQL-запросы. В этом состоянии служба на третьем узле все еще работает, но любой SQL-запрос, связанный с данными, завершается ошибкой.

$ sudo cat /var/lib/mysql/gvwstate.dat # на втором узле
my_uuid: d8fb898f-3ea4-11eb-81d7-ab850ffd5b31
#vwbeg
view_id: 3 c0e9bf47-3ea4-11eb-940b-6fceb3b13836 22
bootstrap: 0
member: c0e9bf47-3ea4-11eb-940b-6fceb3b13836 0
member: d8fb898f-3ea4-11eb-81d7-ab850ffd5b31 0
#vwend
После того, как первый узел был удален из кластера, в нем осталось только два узла (второй и третий). После того, как пропала связь между вторым и третьим, третий узел не знает, что случилось со вторым. Может быть, служба на втором узле продолжает работать, просто есть проблемы в сети. Поэтому третий решает, что он в меньшинстве и отказывается выполнять SQL-запросы. Если на втором узле служба продолжает работать (а у нас так и есть), он тоже считает, что в меньшинстве. Это причина, по которой кол-во узлов должно быть нечетным. Если было четыре узла и из-за проблем в сети они разделились на две равные группы — ни одна из групп не сможет создать кворум.

Как только первый и второй узлы станут доступны — кластер будет воссоздан автоматически — от нас никаких действий не требуется. Но тут есть тонкость — сначала к кластеру должен присоединиться второй узел, а потом уже первый. Первый может присоединиться, если восстановит связь со вторым и третьим узлом — его файл gvwstate.dat содержит три записи member. Второй может присоединиться, если установит связь с третьим узлом — его файл gvwstate.dat содержит две записи member.

Прочитал предыдущий абзац — как-то неоднозначно получилось, поэтому более подробно:

  1. Если связь установят первый и третий — они не смогут восстановить Primary Component — первому нужна связь со вторым и третьим.
  2. Если связь установят первый и второй — они не смогут восстановить Primary Component — первому нужна связь со вторым и третьим.
  3. Если связь установят второй и третий — они смогут восстановить Primary Component — потому что второму нужна связь только с третьим. В кластере будет только два узла — однако это будет уже кворум — и кластер сможет выполнять SQL-запросы от клиентов.
  4. Как только будет выполнен пункт 3 — первый сможет присоединиться — и в кластере будет три узла в состоянии Primary Component.

3. Восстановление после сбоя на трех узлах

До этого мы рассматривали случаи, когда процесс mariadb.service продолжает работать хотя бы на одном узле. Но что делать, если процесс завершен в результате аварии на всех трех узлах? Для начала надо попробовать найти узел, у которого safe_to_bootstrap равен единице — и выполнить на нем galera_new_cluster. Если такого узла нет — надо найти самый продвинутый узел с помощью galera_recovery.

$ sudo galera_recovery # по очереди на всех узлах
WSREP: Recovered position 9885d452-3c5d-11eb-a709-2383d79f0fe4:16
--wsrep_start_position=9885d452-3c5d-11eb-a709-2383d79f0fe4:16

На каком узле число, выделенное красным, будет больше — с того узла и начинаем:

$ sudo galera_new_cluster

Потом запускаем службу mariadb.service на двух других узлах:

$ sudo systemctl start mariadb.service

Поиск: CLI • Linux • MySQL • Ubuntu • Web-разработка • База данных • Сервер • Репликация • MariaD • Galera

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.