Установка кластера Percona XtraDB в Debian 12 Bookworm

Содержание

  1. Содержание
  2. Введение
  3. Настройка первого узла
    1. Настройка базовых репозиториев
    2. Установка пакетов
    3. Настройка репозиториев Percona
    4. Установка пакетов Percona
    5. Настройка и запуск первого узла
    6. Другие настройки
  4. Настройка узла-арбитра
    1. Настройка базовых репозиториев
    2. Установка базовых пакетов
    3. Настройка репозиториев Percona
    4. Установка пакетов Percona
    5. Настройка и запуск арбитра
  5. Настройка нового узла
    1. Настройка базовых репозиториев
    2. Установка базовых пакетов
    3. Настройка репозиториев Percona
    4. Настройка и запуск нового узла
    5. Другие настройки
  6. Включение первого узла в кластер
  7. Настройка прокси
    1. Настройка базовых репозиториев
    2. Установка базовых пакетов
    3. Установка и настройка nginx
  8. Тестирование кластера
    1. Настройка базовых репозиториев
    2. Установка базовых пакетов
    3. Установка и запуск mariadb-slap
  9. Алгоритм восстановления кластера
    1. Остановка арбитра
    2. Выбор первичного компонента
    3. Запуск первичного компонента
    4. Запуск других узлов
    5. Запуск арбитров
    6. Добавление первичного компонента
  10. Возможные проблемы
    1. Остановка более одного узла
    2. Ошибка выбора первичного компонента
    3. Не перезапущен арбитр
  11. Использованные материалы

Введение

Percona XtraDB Cluster - это кластер высокой доступности MySQL. Для превращения обычного MySQL в узел кластера используется плагин Galera. Для защиты от ситуаций расщепления кластера, возникающих при потере связи между частью узлов кластера, кластер должен состояить из нечётного количества узлов. Минимальный кластер должен состояить из трёх узлов. Такой кластер сохраняет работоспособность при аварии или недоступности одного узла.

В качестве усечённого варианта узла кластера можно использовать так называемого арбитра Galera. Арбитр Galera не хранит у себя данные и не может использоваться в качестве источника данных при аварийном восстановлении узла кластера, но принимает участие в голосованиях при конфликтах транзакций или для защиты от расщепления кластера при выбытии отдельных узлов. С использованием арбитра минимальный кластер может состоять из двух полноценных узлов и одного арбитра.

Если описывать логиру работы кластера упрощённо, то можно изложить её следующим образом. Каждый узел кластера, фиксируя транзакцию, записывает её в свой кэш Galera и отправляет другим активным узлам через потоки репликации wsrep. Другие узлы так же сохраняют транзакцию в свой кэш Galera. Транзакция считается зафиксированной, когда применена на большинстве узлов. Если узел временно отсутствовал в кластере, то при воссоединении с кластером он синхронизирует свой кэш Galera с соседними узлами, добавляя в него недостающие транзакции с соседних узлов - это называется инкрементальной передачей состояния или IST. Если же узел отсутствовал в кластере слишком долго, так что из кэшей Galera других узлов уже пропала часть транзакций, необходимых для синхронизации, то выполняется полное копирование данных с узла-донора - это называется передачей снимка состояния или SST.

Ниже приведён пример настройки кластера из двух полноценных узлов и одного арбитра. Узлы кластера имеют IP-адреса:

IP-адрес узла Имя узла Описание
192.168.122.12 mysql0 Первый узел MySQL
192.168.122.13 mysql1 Второй узел MySQL
192.168.122.14 garb Третий узел с арбитром Galera

Сначала настраивается узел mysql0, потом к нему добавляется узел garb с арбитром Galera, потом добавляется узел mysql, после чего узел mysql0 удаляется из кластера и добавляется снова, уже на равноправных началах с остальными узлами кластера.

Точкой подключения к кластеру будет выполнять ещё один узел, который будет проксировать входящие подключения на один из узлов - mysql0 или mysql1. При недоступности первого узла подключения будут проксироваться на второй узел. В качестве прокси-сервера будет использоваться nginx, который в данном случае будет работать на уровне TCP-подключений.

Для полноты картины приведу так же IP-адреса узла с точкой подключения и клиентом:

IP-адрес узла Имя узла Описание
192.168.122.15 nginx Точка подключения - TCP-прокси
192.168.122.16 slap Узел-клиент

Настройка первого узла

Настройка базовых репозиториев

Пропишем в файл /etc/apt/sources.list репозитории Debian 12 Bookworm, расположенные на зеркале mirror.ufanet.ru:

deb http://mirror.ufanet.ru/debian/ bookworm main contrib non-free-firmware
deb http://mirror.ufanet.ru/debian/ bookworm-updates main contrib non-free-firmware
deb http://mirror.ufanet.ru/debian/ bookworm-proposed-updates main contrib non-free-firmware
deb http://mirror.ufanet.ru/debian-security/ bookworm-security main contrib non-free-firmware

Отключим установку предлагаемых зависимостей, создав файл /etc/apt/apt.conf.d/suggests со следующим содержимым:

APT::Install-Suggests "false";

Отключим установку рекомендуемых зависимостей, создав файл /etc/apt/apt.conf.d/recommends со следующим содержимым:

APT::Install-Recommends "false";

Для ограничения объёма кэша пакетов 200 мегабайтами, хранящегося в каталоге /var/cache/apt/archives/, создадим файл /etc/apt/apt.conf.d/cache со следующим содержимым:

APT::Cache-Limit "209715200";

Чтобы уменьшить время ожидания при недоступности репозитория пятью секундами, создадим файл /etc/apt/apt.conf.d/timeouts со следующим содержимым:

Acquire::http::Timeout "5";
Acquire::https::Timeout "5";
Acquire::ftp::Timeout "5";

Обновим список пакетов, доступных через репозитории:

# apt-get update

Установка пакетов

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

# apt-get upgrade
# apt-get dist-upgrade

Установим дополнительные пакеты, которые могут пригодиться при работе с системой:

# apt-get install acpi-support-base vim less apt-file binutils sysstat tcpdump file dnsutils telnet psmisc traceroute net-tools man-db bzip2 ca-certificates apt-transport-https wget unzip sudo needrestart

Я привык использовать в качестве редактора по умолчанию vim, поэтому выберу его как системный редактор по умолчанию:

# update-alternatives --set editor /usr/bin/vim.basic

Настройка репозиториев Percona

Устанавливаем утилиты, необходимые для пакета percona-release:

# apt-get install lsb-release curl gnupg2

Скачаем и установим утилиту для управления репозиториями Percona:

# wget https://repo.percona.com/apt/percona-release_latest.bookworm_all.deb
# dpkg -i percona-release_latest.bookworm_all.deb

Для установки Percona XtraDB Cluster Server добавляем репозитории pxb-24, tools и pxc-57:

# percona-release enable-only original
# percona-release enable prel
# percona-release enable tools
# percona-release enable pxb-24
# percona-release enable pxc-57

Обновим список пакетов, доступных через репозитории:

# apt-get update

Установка пакетов Percona

Установим инструменты Percona, утилиту XtraBackup (а также socat и pigz для использования вместе с ней), утилиту MySQLTuner и пакет с узлом кластера Percona:

# apt-get install percona-toolkit socat pigz percona-xtrabackup-24 percona-xtradb-cluster-server-5.7 mysqltuner

Укажем системе, что в качестве MySQL в системе будет использоваться узел кластера Percona:

# update-alternatives --set my.cnf /etc/mysql/percona-xtradb-cluster.cnf

В процессе установки пакета percona-xtradb-cluster-server-5.7 нужно будет указать пароль пользователя root - администратора БД. Чтобы в дальнейшем, работая под пользователем root, подключаться к MySQL от имени администратора БД root без ввода пароля, создадим в доамшнем каталоге пользователя root файл кофигурации /root/.my.cnf с настройками для подключения клиента MySQL к СУБД:

[client]
user = root
password = $ecretPa$$w0rd

Сделаем владельцем этого файла польователя root и дадим доступ к этому файлу только самому пользователю root:

# chown root:root /root/.my.cnf
# chmod u=rw,go= /root/.my.cnf

Настройка и запуск первого узла

Сначала настроим сам сервер MySQL. Для этого приведём файл конфигурации /etc/mysql/percona-xtradb-cluster.conf.d/mysqld.cnf к следующему виду:

[mysqld]
server_id = 1
datadir = /var/lib/mysql
socket = /var/run/mysqld/mysqld.sock
log_error = /var/log/mysql/error.log
pid_file = /var/run/mysqld/mysqld.pid
#log_bin
#log_slave_updates = OFF
#expire_logs_days = 1

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic_links = OFF

# general settings
ssl = OFF
sql_mode =
performance_schema = OFF
disabled_storage_engines = MyISAM,MEMORY
explicit_defaults_for_timestamp = ON

# connections
max_connections = 100
max_user_connections = 80
thread_cache_size = 100
thread_handling = one-thread-per-connection
max_connect_errors = 18446744073709551615

# thread buffers
sort_buffer_size = 2M
read_buffer_size = 128K
read_rnd_buffer_size = 256K
join_buffer_size = 256K
tmp_table_size = 32M

# innodb settings
innodb_file_per_table = ON
innodb_flush_method = O_DIRECT
innodb_buffer_pool_size = 512M
innodb_buffer_pool_dump_at_shutdown = OFF
innodb_buffer_pool_load_at_startup = OFF

# innodb log settings
innodb_log_file_size = 32M
innodb_log_files_in_group = 2
innodb_flush_log_at_trx_commit = 2

# query cache
query_cache_type = OFF
query_cache_size = 0
query_cache_limit = 0

# timeouts
wait_timeout = 3600
net_write_timeout = 300

# slow queries
log_timestamps = SYSTEM
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slowquery.log
long_query_time = 3

Внимательно просмотрите приведённые выше настройки - возможно часть из них вам покажутся спорными и вы захотите их поменять. Например, включить SSL и performance_schema, изменить максимальное количество подключений или объём буфера InnoDB и т.д. Настройке производительности MySQL посвящены отдельные статьи.

Пропишем в файл конфигурации /etc/mysql/percona-xtradb-cluster.conf.d/wsrep.cnf следующие настройки:

[mysqld]
# Path to Galera library
wsrep_provider = /usr/lib/galera3/libgalera_smm.so

# Cluster connection URL contains IPs of nodes
#If no IP is found, this implies that a new cluster needs to be created,
#in order to do that you need to bootstrap this node
wsrep_cluster_address = gcomm://

# In order for Galera to work correctly binlog format should be ROW
binlog_format = ROW

# MyISAM storage engine has only experimental support
default_storage_engine = InnoDB

# Slave thread to use
wsrep_slave_threads = 8

wsrep_log_conflicts = ON

# This changes how InnoDB autoincrement locks are managed and is a requirement for Galera
innodb_autoinc_lock_mode = 2

# Node IP address
wsrep_node_address = 192.168.122.12
# Cluster name
wsrep_cluster_name = mysql-cluster

#If wsrep_node_name is not specified,  then system hostname will be used
wsrep_node_name = mysql0

#pxc_strict_mode allowed values: DISABLED,PERMISSIVE,ENFORCING,MASTER
pxc_strict_mode = DISABLED

# SST method
wsrep_sst_method = xtrabackup-v2

#Authentication for SST method
wsrep_sst_auth = sstuser:$$Tp4$$w0rd
wsrep_sst_donor = mysql1

Назначение опций:

  • wsrep_cluster_name - имя кластера, должно совпадать на всех узлах кластера,
  • wsrep_cluster_address - здесь указываются через запятую IP-адреса соседних узлов. Перед адресами должен быть префикс gcomm://,
  • wsrep_node_name - собственное имя узла. Если опция не указано будет использоваться имя системы из файла /etc/hostname,
  • wsrep_node_address - собственный IP-адрес узла,
  • wsrep_sst_method - метод полученя полной копии данных, если узел не смог синхронизироваться с кластером инкрементально,
  • wsrep_sst_donor - имя узла, который будет использоваться в качестве источника для получения полной копии данных,
  • wsrep_sst_auth - имя пользователя и пароль для доступа к узлу-источнику для получения полной копии данных.

Обратите внимание, что в опции wsrep_cluster_address не указаны адреса других узлов кластера. Это позволит запустить узел в режиме первичного компонента, который будет использоваться для настройки последующих узлов.

Запустим MySQL:

# systemctl start mysql

Для того, чтобы этот узел в дальнейшем смог получить полную копию с других узлов, создадим пользователя sstuser и дадим его доступ с IP-адреса настраиваемого узла с помощью следующих выражений:

CREATE USER 'sstuser'@'192.168.122.12' IDENTIFIED BY '$$Tp4$$w0rd';
GRANT LOCK TABLES, PROCESS, RELOAD, REPLICATION CLIENT ON *.* TO 'sstuser'@'192.168.122.12';

Другие настройки

Percona XtraDB Cluster Server версии 5.7 поставляется без service-файла для systemd. Ранее я уже описывал в статье Решение проблемы Could not increase number of max open files в MySQL создание service-файла.

Для редактирования service-файла воспользуемся следующей командой:

# systemctl edit --full mysql

И приведём файл к следующему виду:

#
# Percona XtraDB Cluster Server systemd service file
#

[Unit]
Description=Percona XtraDB Cluster Server
After=network.target

[Install]
WantedBy=multi-user.target

[Service]
Type=forking
User=mysql
Group=mysql
PermissionsStartOnly=true
EnvironmentFile=-/etc/default/mysql
LimitNOFILE=infinity
AmbientCapabilities=CAP_IPC_LOCK
ExecStartPre=/usr/share/mysql/mysql-systemd-start pre
ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid $MYSQLD_OPTS
TimeoutSec=0
Restart=on-failure
RestartPreventExitStatus=1

Для того, чтобы сообщить systemd о том, что service-файл изменился, воспользуемся такой командой:

# systemctl daemon-reload

Debian 12 Bookworm поставляется без конфигурации для ротации журналов MySQL для logrotate, поскольку в системе по умолчанию для сбора журналов используются средства jourald. Но в приведённом выше файле конфигурации /etc/mysql/percona-xtradb-cluster.conf.d/mysqld.cnf используются файлы журналов /var/log/mysql/error.log и /var/log/mysql/slowquery.log. Для самих файлов журналов нужно создать каталог /var/log/mysql, а для ротации журналов - файл /etc/logrotate.d/mysql. Сделаем это:

# mkdir /var/log/mysql
# chown mysql:adm /var/log/mysql
# chmod u=rwx,g=rx,o= /var/log/mysql
# cat > /etc/logrotate.d/mysql <<END
/var/log/mysql/error.log /var/log/mysql/slowquery.log {
        daily
        rotate 7
        missingok
        create 640 mysql adm
        compress
        sharedscripts
        postrotate
                test -x /usr/bin/mysqladmin || exit 0

                MYADMIN="/usr/bin/mysqladmin --defaults-file=/root/.my.cnf"
                if [ -z "`$MYADMIN ping 2>/dev/null`" ]; then
                        # Really no mysqld or rather a missing debian-sys-maint user?
                        # If this occurs and is not a error please report a bug.
                        if ps cax | grep -q mysqld; then
                                exit 1
                        fi
                else
                        $MYADMIN flush-logs
                fi
        endscript
}
END

В файле /etc/logrotate.d/mysql используются учётные данные из файла /root/.my.cnf для того, чтобы заставить MySQL переоткрыть файлы журналов.

Настройка узла-арбитра

Настройка базовых репозиториев

Всё аналогично настройке первого узла.

Установка базовых пакетов

Всё аналогично настройке первого узла.

Настройка репозиториев Percona

Здесь всё аналогично настройке первого узла, за исключением того, что репозитории с утилитой XtraBackup и инструментами Percona здесь не нужны:

# percona-release enable-only original
# percona-release enable prel
# percona-release enable pxc-57

Установка пакетов Percona

Установим пакет с арбитром Galera для кластера Percona XtraDB:

# apt-get install percona-xtradb-cluster-garbd-5.7

Настройка и запуск арбитра

Приведём файл /etc/default/garbd к следующему виду:

# Copyright (C) 2012 Codership Oy
# This config file is to be sourced by garb service script.

# A comma-separated list of node addresses (address[:port]) in the cluster
GALERA_NODES="192.168.122.12,192.168.122.13"

# Galera cluster name, should be the same as on the rest of the nodes.
GALERA_GROUP="mysql-cluster"

# Optional Galera internal options string (e.g. SSL settings)
# see http://galeracluster.com/documentation-webpages/galeraparameters.html
GALERA_OPTIONS="base_dir=/var/lib/galera"

# Log file for garbd. Optional, by default logs to syslog
# Deprecated for CentOS7, use journalctl to query the log for garbd
# LOG_FILE=""

В файле используются следующие опции:

  • GALERA_NODES - здесь указываются через запятую IP-адреса соседних узлов, префикс gcomm:// тут не указывается,
  • GALERA_GROUP - имя кластера, должно совпадать на всех узлах кластера,
  • GALERA_OPTIONS - дополнительные опции для демона-арбитра Galera. В примере указан каталог для хранения временных файлов,
  • LOG_FILE - файл журнала.

Лучше не указывать файл журнала, поскольку нет возможности подать сигнал арбитру переоткрыть журнал. Из-за этого могут возникнуть проблемы с ротацией журналов. По умолчанию сообщения пишутся в syslog или journald, пришедший ему на замену.

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

Осталось запустить демон-арбитр Galera:

# systemctl start garbd

Для просмотра журналов можно воспользоваться следующей командой:

# journalctl -u garbd

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

# journalctl -fu garbd

Настройка нового узла

Настройка базовых репозиториев

Всё аналогично настройке первого узла.

Установка базовых пакетов

Всё аналогично настройке первого узла.

Настройка репозиториев Percona

Всё аналогично настройке первого узла.

Настройка и запуск нового узла

Здесь всё аналогично настройке и запуску первого узла, за исключением значений некоторых опций в файле конфигурации /etc/mysql/percona-xtradb-cluster.conf.d/wsrep.cnf. Ниже приведены значения для отличающихся опций:

wsrep_cluster_address = gcomm://192.168.122.12,192.168.122.14
wsrep_node_address = 192.168.122.13
wsrep_node_name = mysql1
wsrep_sst_donor = mysql0

Обратите внимание, что на этот раз в опции wsrep_cluster_address на этот раз перечислены адреса всех других узлов кластера. Донором для этого узла кластера будет узел mysql0, настроенный первым.

Для того, чтобы новый узел в смог получить полную копию с ранее настроенного нами узла, создадим на первом узле пользователя sstuser и дадим его доступ с IP-адреса настраиваемого узла с помощью следующих выражений:

CREATE USER 'sstuser'@'192.168.122.13' IDENTIFIED BY '$$Tp4$$w0rd';
GRANT LOCK TABLES, PROCESS, RELOAD, REPLICATION CLIENT ON *.* TO 'sstuser'@'192.168.122.13';

Запустим MySQL:

# systemctl start mysql

После запуска новый узел должен выполнить полное копирование данных с первого узла.

Другие настройки

Всё аналогично настройке первого узла.

Включение первого узла в кластер

Когда настроены все узлы, нужно вернуться к узлу, настроенному первым, который использовался в качестве первичного компонента кластера, и включить его в кластера на равных началах с остальными узлами. Для этого пропишем в файл его конфигурации /etc/mysql/percona-xtradb-cluster.conf.d/wsrep.cnf адреса других узлов следующим образом:

wsrep_cluster_address = gcomm://192.168.122.13,192.168.122.14

И применим эти настройки к уже работающему узлу, выполнив запрос следующего вида:

SET GLOBAL wsrep_cluster_address = 'gcomm://192.168.122.13,192.168.122.14';

Настройка прокси

Настройка базовых репозиториев

Всё аналогично настройке первого узла.

Установка базовых пакетов

Всё аналогично настройке первого узла.

Установка и настройка nginx

Установим необходимые пакеты:

# apt-get install nginx libnginx-mod-stream

Приведём файл конфигурации /etc/nginx/nginx.conf к следующему виду:

user www-data;
worker_processes 1;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;
load_module modules/ngx_stream_module.so;

events {
        worker_connections 20480;
}
worker_rlimit_nofile 65535;

stream {
        log_format proxy '$remote_addr [$time_local] '
                '$protocol:$server_addr:$server_port $upstream_addr '
                '$status $bytes_sent $bytes_received $session_time';

        upstream dbs {
                server 192.168.122.12:3306 max_fails=30 fail_timeout=30s;
                server 192.168.122.13:3306 backup;
        }

        server {
                listen 192.168.122.15:3306 so_keepalive=on;

                access_log /var/log/nginx/mysql.log proxy;

                proxy_connect_timeout 20s;
                proxy_timeout 1m;
                proxy_socket_keepalive on;
                proxy_pass dbs;

                allow 192.168.122.16;
                deny all;
        }
}

Пример выше не учитывает, что nginx может выполнять какие-то иные функции, кроме проксирования TCP-подключений к узлам кластера MySQL. Входящие подключений принимаются на TCP-порт 3306 на IP-адресе 192.168.122.15, разрешено подключаться клиентам с IP-адресом 192.168.122.16.

При поступлении входящего подключения оно проксируется на узел кластера mysql0, но если в течение 30 секунд не удалось установить 30 подключений или больше, то подключения будут направляться на узел mysql1.

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

# systemctl restart nginx

Тестирование кластера

Для тестирования кластера настроим ещё один узел, на котором будет работать утилита mariadb-slap из пакета mariadb-client.

Настройка базовых репозиториев

Всё аналогично настройке первого узла.

Установка базовых пакетов

Всё аналогично настройке первого узла.

Установка и запуск mariadb-slap

Установим в систему пакет mariadb-client с утилитой mariadb-slap:

# apt-get install mariadb-client

Теперь подключимся к любому из узлов кластера с помощью MySQL под пользователем root, создадим тестовую базу данных, пользователя для тестирования, выдадим пользователю доступ к этой базе данных и применим выданные права:

CREATE DATABASE `mysqlslap` DEFAULT CHARACTER SET latin1;
CREATE USER 'mysqlslap'@'192.168.122.16' IDENTIFIED BY 'Sl4pP4$$w0rd';
GRANT ALL PRIVILEGES ON `mysqlslap`.* TO 'mysqlslap'@'192.168.122.16';
FLUSH PRIVILEGES;

Теперь можно запустить утилиту mariadb-slap для создания нагрузки на один из узлов кластера:

$ while true ; do mariadb-slap -a -h192.168.122.16 -umysqlslap -pSl4pP4$$w0rd -c10 --number-of-queries 1000000 ; done

Утилита запущена на генерацию миллиона запросов в 10 подключениях, которые направляет к узлу-прокси с nginx. При любых ошибках выполнения запросов утилита завершает работу, но мне нужна постоянная нагрузка, поэтому я запустил утилиту в бесконечном цикле.

Утилита генерирует только запросы двух видов: SELECT и INSERT. Запросы идут только к одной таблице t1, в которой есть числовое и текстовое поля, но нет каких-либо ключей или индексов. Тем не менее, для тестирования работы кластера в общих чертах этого достаточно.

Алгоритм восстановления кластера

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

Остановка арбитра

Перед восстановлением работы кластера из первичного компонента необходимо остановить арбитров. Арбитр запоминает последнюю применённую в кластере транзакцию, а после восстановления работы кластера из первичного компонента её номер может уменьшиться. В таком случае арбитр не даст запустить другие узлы, либо прервёт их работу, если их всё-таки удастся запустить.

Выбор первичного компонента

Первым делом нужно определить, какой из узлов будем использовать в качестве первичного компонента. Определить его можно по содержимому файла /var/lib/mysql/grastate.dat, который имеет следующий вид:

# GALERA saved state
version: 2.1
uuid:    ea88f6e9-fd43-11ee-898c-d771aa270ca7
seqno:   -1
safe_to_bootstrap: 0

При корректном завершении работы всех узлов кластера последний узел отметит в своём файле в поле safe_to_bootstrap значение 1. В таком случае именно этот узел и стоит использовать в качестве первичного компонента при повторном запуске кластера.

Но для полной уверенности стоит всё же проверить значение поля seqno на всех узлах. Из всех узлов кластера нужно выбрать такой узел, у которого значение в поле seqno будет максимальным. Узел записывает в это поле значение, отличное от -1, только при корректном завершении работы. У работающего узла в этом поле всегда будет значение -1, которое останется в этом файле в случае аварийного завершения процесса mysqld. Для того, чтобы узнать действительное значение поля seqno, нужно запустить mysqld_safe с опцией --wsrep-recover следующим образом:

# mysqld_safe --wsrep-recover
2024-04-22T06:34:34.983844Z mysqld_safe Logging to '/var/log/mysql/error.log'.
2024-04-22T06:34:34.987268Z mysqld_safe Logging to '/var/log/mysql/error.log'.
2024-04-22T06:34:35.031375Z mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
2024-04-22T06:34:35.064395Z mysqld_safe WSREP: Running position recovery with --log_error='/var/lib/mysql/wsrep_recovery.8NccxK' --pid-file='/var/lib/mysql/mysql1-recover.pid'
2024-04-22T06:34:37.938837Z mysqld_safe WSREP: Recovered position ea88f6e9-fd43-11ee-898c-d771aa270ca7:618447
2024-04-22T06:34:40.802585Z mysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended

В предпоследней строке можно найти последние значения полей uuid и seqno непосредственно перед аварийным завершением работы узла. Эти значения можно вручную внести в файл /var/lib/mysql/grastate.dat.

Запуск первичного компонента

Итак, когда выбран узел с максимальным значением seqno, нужно запустить первичный компонент. Для этого открываем на редактирование файл /var/lib/mysql/grastate.dat и вносим в поле safe_to_bootstrap значение 1.

Далее открываем на редактирование файл /etc/mysql/percona-xtradb-cluster.conf.d/wsrep.cnf, комментируем прежнее значение опции wsrep_cluster_address и прописываем эту опцию без адресов других узлов:

wsrep_cluster_address = gcomm://

Теперь можно запустить первичный компонент, как обычно:

# systemctl start mysql

Запуск других узлов

Далее, не внося никаких изменений в настройки, запускаем все остальные узлы - как полноценные узлы с MySQL:

# systemctl start mysql

Если эти узлы не сильно отстали от узла, запущенного первым, то они должны догнать его с использованием кэша транзакций Galera с использованием инкрементальной процедуры синхронизации - IST. В противном случае может потребоваться полное копирование данных с узла-донора - SST. Чтобы не мешать работе приложения, лучше запускать последующие узлы только после после завершения процедуры полного копирования данных предыдущим узлом.

Запуск арбитров

Последним нужно запустить арбитр Galera:

# systemctl start grabd

Добавление первичного компонента

Когда запущены все узлы кластера, включая арбитра Galera, нужно включить в кластер первичный компонент, чтобы он стал полноценным участником кластера. Для этого нужно вернуть в файл конфигурации /etc/mysql/percona-xtradb-cluster.conf.d/wsrep.cnf узла, выбранного для запуска кластера в качестве первичного компонента, прежнее значение опции wsrep_cluster_address.

Далее, не перезапуская узел, применим его штатные настройки, присвоив глобальной переменной wsrep_cluster_address актуальные значения из файла конфигурации, например, следующим образом:

SET GLOBAL wsrep_cluster_address = 'gcomm://192.168.122.13,192.168.122.14';

Возможные проблемы

Остановка более одного узла

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

  1. Останавливаем MySQL сначала на первом узле,

  2. Останавливаем MySQL на втором узле,

  3. Запускаем MySQL на любом узле - он не запускается и пишет в журналы ошибки следующего вида:

    2024-04-22T16:26:30.864995+05:00 0 [ERROR] WSREP: gcs/src/gcs_group.cpp:group_check_proto_ver():262: Group requested repl_proto_ver: 127, max supported by this node: 9.Upgrade the node before joining this group.Need to abort.
    2024-04-22T16:26:30.865052+05:00 0 [ERROR] WSREP: gcs/src/gcs_group.cpp:group_check_proto_ver():263: Group requested appl_proto_ver: 127, max supported by this node: 3.Upgrade the node before joining this group.Need to abort.
    2024-04-22T16:26:30.865112+05:00 0 [Note] WSREP: /usr/sbin/mysqld: Terminated.
    

Арбитр на третьем узле тоже завершает работу с сообщениями об ошибках следующего вида:

apr 22 16:28:02 garb garbd[2394]: (57606ccd, 'tcp://0.0.0.0:4567') turning message relay requesting off
apr 22 16:28:18 garb garbd[2394]: failed to open gcomm backend connection: 110: failed to reach primary view (pc.wait_prim_timeout): 110 (Connection timed out)
                                              at gcomm/src/pc.cpp:connect():161
apr 22 16:28:18 garb garbd[2394]: gcs/src/gcs_core.cpp:gcs_core_open():209: Failed to open backend connection: -110 (Connection timed out)
apr 22 16:28:18 garb garbd[2394]: gcs/src/gcs.cpp:gcs_open():1528: Failed to open channel 'mysql-cluster' at 'gcomm://192.168.122.12,192.168.122.13': -110 (Connection timed out)
apr 22 16:28:18 garb garbd[2394]: Shifting CLOSED -> DESTROYED (TO: 0)
apr 22 16:28:18 garb garbd[2394]: Exception in creating receive loop: Failed to open connection to group: 110 (Connection timed out)
                                              at garb/garb_gcs.cpp:Gcs():35

Ошибка выбора первичного компонента

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

2024-04-22T16:40:17.246256+05:00 0 [ERROR] WSREP: gcs/src/gcs_group.cpp:group_post_state_exchange():353: Reversing history: 214754 -> 206742, this member has applied 8012 more events than the primary component.Data loss is possible. Must abort.

При следующей попытке запустить его, он сообщит о несопадении UUID и невозможности выполнить инкрементное копирование:

2024-04-22T16:44:36.189699+05:00 1 [Note] WSREP: Local UUID: 00000000-0000-0000-0000-000000000000 != Group UUID: 5f0e9433-008e-11ef-8f02-a3c616135399
2024-04-22T16:44:36.190239+05:00 1 [Note] WSREP: State gap can't be serviced using IST. Switching to SST
2024-04-22T16:44:36.190262+05:00 1 [Note] WSREP: Failed to prepare for incremental state transfer: Local state UUID (00000000-0000-0000-0000-000000000000) does not match group state UUID (5f0e9433-008e-11ef-8f02-a3c616135399): 1 (Operation not permitted)
         at galera/src/replicator_str.cpp:prepare_for_IST():518. IST will be unavailable.

После чего приступит к полному копированию данных:

2024-04-22T16:44:36.198008+05:00 0 [Note] WSREP: Member 1.0 (mysql1) requested state transfer from 'mysql0'. Selected 0.0 (mysql0)(SYNCED) as donor.
2024-04-22T16:44:36.198043+05:00 0 [Note] WSREP: Shifting PRIMARY -> JOINER (TO: 234541)
2024-04-22T16:44:36.198072+05:00 1 [Note] WSREP: Requesting state transfer: success, donor: 0
2024-04-22T16:44:36.198083+05:00 1 [Note] WSREP: GCache history reset: 00000000-0000-0000-0000-000000000000:0 -> 5f0e9433-008e-11ef-8f02-a3c616135399:234467
2024-04-22T16:44:37.108494+05:00 0 [Note] WSREP: (b01903d4, 'tcp://0.0.0.0:4567') turning message relay requesting off
2024-04-22T16:44:40.859131+05:00 WSREP_SST: [INFO] Streaming with xbstream
2024-04-22T16:44:40.885615+05:00 WSREP_SST: [INFO] Proceeding with SST.........
2024-04-22T16:44:40.979025+05:00 WSREP_SST: [INFO] ............Waiting for SST streaming to complete!
2024-04-22T16:46:02.274180+05:00 0 [Note] WSREP: 0.0 (mysql0): State transfer to 1.0 (mysql1) complete.
2024-04-22T16:46:02.277924+05:00 WSREP_SST: [INFO] Preparing the backup at /var/lib/mysql//.sst
2024-04-22T16:46:02.282081+05:00 0 [Note] WSREP: Member 0.0 (mysql0) synced with group.
2024-04-22T16:46:07.559744+05:00 WSREP_SST: [INFO] Moving the backup to /var/lib/mysql/
2024-04-22T16:46:07.685604+05:00 WSREP_SST: [INFO] Galera co-ords from recovery: 5f0e9433-008e-11ef-8f02-a3c616135399:238074
2024-04-22T16:46:07.712104+05:00 0 [Note] WSREP: SST complete, seqno: 238074

Не перезапущен арбитр

Если не перезапустить арбитра перед настройкой кластера из первичного компонента, то не получится запустить другие узлы с MySQL. Арбитр будет выводить сообщения об ошибках следующего вида:

apr 22 17:07:41 garb garbd[2543]: 5f529535 conflicting prims: my prim: view_id(PRIM,5f529535,63) other prim: view_id(PRIM,dc5f5b6c,1)
apr 22 17:07:41 garb garbd[2543]: 5f529535 discarding other prim view: older overrides

Более того, сам арбитр может аварийно заврешить работу с сообщениями об ошибках следующего вида:

apr 22 17:10:48 garb garbd[2543]: gcs/src/gcs_group.cpp:group_post_state_exchange():357: Reversing history: 318747 -> 317293, this member has applied 1454 more events than the primary component.Data loss is possible. Must abort.
apr 22 17:10:49 garb garbd[2543]: gcs/src/gcs_core.cpp:gcs_core_destroy():1215: Calling destroy() before close().

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