Появилась задача создать надёжный сервис БД типа 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 sst_user@'%' IDENTIFIED BY 'dbpass';
GRANT ALL PRIVILEGES on *.* to sst_user@'%';
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
При использовании прокси-серверов авторизация на серверах БД идёт с прокси-сервера, а значит это надо предусмотреть при настройках пользователей в БД.