Cluster MariaDB Galera 10.0

Появилась задача создать надёжный сервис БД типа MySQL. Я предпочитаю MariaDB, которая с версии 10 поддерживает работу master-master, но данная схема работает только для двух серверов и плохо относится к ситуации split-brain.

Сервер

Выбор пал на MariaDB Galera, которая позволяет использовать multi-master, а в ситуации split-brain работает механизм minority opinion.

Так как это не для домашних целей, платформой будет CentOS 7.

Имеем 3 сервера с адресами:

  • 10.0.0.1 - galera1;
  • 10.0.0.2 - galera2;
  • 10.0.0.3 - galera3.

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

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

# setenforce 0
# systemctl stop firewalld

Добавляем репозиторий в файле /etc/yum.repos.d/MariaDB.repo:

[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.0/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

Ставим необходимые пакеты, запускаем сервер БД и проводим базовую настройку (ставим пароль на root, удаляем тестовую БД и отключаем удалённый доступ для root):

# yum  install socat MariaDB-Galera-server MariaDB-client
# service mysql start
# /usr/bin/mysql_secure_installation

Добавляем пользователя для служебных процессов на сервере:

# mysql -u root -p
DELETE FROM mysql.user WHERE user='';
GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY 'dbpass';
GRANT USAGE ON *.* to [email protected]'%' IDENTIFIED BY 'dbpass';
GRANT ALL PRIVILEGES on *.* to [email protected]'%';
FLUSH PRIVILEGES;
quit

После этого тормозим сервер БД:

# service mysql stop

Добавляем настройки для кластера в конец файла /etc/my.cnf.d/server.cnf (меняя $host_ip и $host_name на значения для конкретного сервера):

binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
innodb_locks_unsafe_for_binlog=1
query_cache_size=0
query_cache_type=0
bind-address=0.0.0.0
datadir=/var/lib/mysql
innodb_log_file_size=100M
innodb_file_per_table
innodb_flush_log_at_trx_commit=2
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address="gcomm://10.0.0.1,10.0.0.2,10.0.0.3"
wsrep_cluster_name='galera_cluster'
wsrep_node_address='$host_ip'
wsrep_node_name='$host_name'
wsrep_sst_method=rsync
wsrep_sst_auth=sst_user:dbpass

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

# /etc/rc.d/init.d/mysql start --wsrep-new-cluster

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

# service mysql start

Статус кластера можно посмотреть следующей командой:

# mysql -u root -p -e "show status like 'wsrep%'"

Proxy

Создав кластер на базе MariaDB Galera задаёшься вопросом: что делать с тремя IP-адресами?

Принято решение поставить специализированный прокси-сервер для этих целей. Подходящие кандидаты:

  • Oracle MySQL Proxy - проект почти не развивается;
  • Severalnines ClusterControl - интересный продукт с красивой графической оболочкой, но работающий на уровне IP-трафика, что снижает число доступных плюшек;
  • Galera Load Balancer - проект похоже заброшен;
  • ProxySQL - нашёл только недавно (намного позже написания данной статьи), по описанию крут, но руки до него не дошли;
  • MariaDB MaxScale - от создателей MariaDB.

Для начала решил поиграться с последним продуктом.

Ставится давольно просто:

  • Зарегистрироваться на сайте MariaDB;
  • Перейти в секцию Download;
  • Установить репозиторий и сам maxscale согласно инструкции на сайте.

Традиционно в начале понижаем уровень безопасности:

# setenforce 0
# systemctl stop firewalld

Приводим настройки /etc/maxscale.cnf к следующему виду:

[maxscale]
threads=4
[Galera Monitor]
type=monitor
module=galeramon
servers=server1,server2,server3
user=sst_user
passwd=dbpass
monitor_interval=10000
disable_master_failback=1
[qla]
type=filter
module=qlafilter
options=/tmp/QueryLog
[fetch]
type=filter
module=regexfilter
match=fetch
replace=select
[hint]
type=filter
module=hintfilter
[Read Connection Router]
type=service
router=readconnroute
servers=server1,server2,server3
user=sst_user
passwd=dbpass
router_options=slave
[RW Split Router]
type=service
router=readwritesplit
servers=server1,server2,server3
user=sst_user
passwd=dbpass
max_slave_connections=100%
router_options=slave_selection_criteria=LEAST_CURRENT_OPERATIONS
[Debug Interface]
type=service
router=debugcli
[CLI]
type=service
router=cli
[Read Connection Listener]
type=listener
service=Read Connection Router
protocol=MySQLClient
port=4008
socket=/var/lib/maxscale/readconn.sock
[RW Split Listener]
type=listener
service=RW Split Router
protocol=MySQLClient
port=3306
[Debug Listener]
type=listener
service=Debug Interface
protocol=telnetd
address=127.0.0.1
port=4442
[CLI Listener]
type=listener
service=CLI
protocol=maxscaled
port=6603
[server1]
type=server
address=10.0.0.1
port=3306
protocol=MySQLBackend
[server2]
type=server
address=10.0.0.2
port=3306
protocol=MySQLBackend
[server3]
type=server
address=10.0.0.3
port=3306
protocol=MySQLBackend

В итоге получили следующие данные по портам:

  • 3306 — MaxScale автоматически назначил один из серверов мастером и будет направлять на него все запросы на запись, а остальным запросы на чтение;
  • 4008 — работает в режиме round-robin;

Если зайти локально по ssh, можно получить полезную информацию о состоянии кластера:

# maxadmin -u admin
Password: mariadb
MaxScale> show servers

При использовании прокси-серверов авторизация на серверах БД идёт с прокси-сервера, а значит это надо предусмотреть при настройках пользователей в БД.