01 前言
Galera Cluster是Mysql基于innodb引擎,来实现multi-master及数据实时同步,并且免费开源的高可用方案。其特点有:对业务层提供透明接口;数据库读写自动分发各节点,无需手动做读写分离;并且统一管理集群成员(节点自动增删)。
Galera Cluster的官方网站为http://galeracluster.com,具体的特性请查询官网资料。
Galera Cluster常用的方案有三种:Galera Cluster for MySQL、MariaDB Galera Cluster、Percona XtraDB Cluster。本文主要使用MariaDB Galera Cluster来做演示。
本文转自我个人的公众号:天目星 ,请大家多多关注。
一、使用的软件与架构图
linux:CentOS 7.5.1804
MariaDB-server:MariaDB-server-10.2.23
MariaDB-client:MariaDB-client-10.2.23
MariaDB-common:MariaDB-common-10.2.23
MariaDB-backup:MariaDB-backup-10.2.23
galera:galera-25.3.26
二、安装软件
1、使用yum源安装
我们使用三台主机做测试环境
node1:192.168.159.45
node2:192.168.159.46
node3:192.168.159.47
在每台主机增加一个repo文件
$ vim /etc/yum.repos.d/mariadb.repo
#
[mariadb]
name=MariaDB
baseurl=http://yum.mariadb.org/10.2/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
#
在三台节点中安装
$ yum install galera MariaDB-server MariaDB-client \
MariaDB-backup
2、配置
设置galera cluster的基础配置
节点1
$ vim /etc/my.cnf.d/server.cnf
#
[mysqld]
server_id=1 #mysql ID,每台不一样
datadir=/data #提前创建好文件夹,并授予mysql用户读写权限
user=mysql #启动mariadb的用户
skip-external-locking
skip-name-resolve
character-set-server=utf8
[galera]
wsrep_on=ON #开启集群同步复制模式
wsrep_causal_reads=ON #各节点应用完事务才返回查询请求,可以避免脏读
wsrep_provider_options="gcache.size=1G" #按照binglog一小时产生的大小*4来配置
wsrep_certify_nonPK=ON #为没有主键的表自动生成主键
wsrep_provider=/usr/lib64/galera/libgalera_smm.so #wsrep库的位置
wsrep_cluster_name=My-Cluster #集群名称
wsrep_cluster_address="gcomm://192.168.159.45,192.168.159.46,192.168.159.47" #集群成员
wsrep_node_name=node1 #此节点的名称
wsrep_node_address=192.168.159.45 #此节点的IP地址
wsrep_slave_threads=1 #并行应用Galera集群的从属线程数,如果经常出现一致性问题,请设置为1
wsrep_sst_method=mariabackup #集群同步的模式,测试可以使用rsync,如果生产环境请使用mariabackup
wsrep_sst_auth='root:123456' #集群同步开启验证
default_storage_engine=InnoDB #设置默认创建的数据库引擎为InnoDB
log-bin=/data/mysql-bin #开启binglog,可以用于从库复制
log_slave_updates=1 #配合上一条用于从库复制用
binlog_format=row #binglog记录模式
query_cache_size=0 #配合集群关闭查询缓存
innodb_autoinc_lock_mode=2 #主键自增修改为交叉模式
innodb_flush_log_at_trx_commit=0 #关闭此参数会提升性能
innodb_buffer_pool_size=128M #根据内存情况设置大小
节点2
$ vim /etc/my.cnf.d/server.cnf
#
[mysqld]
server_id=2
datadir=/data
user=mysql
skip-external-locking
skip-name-resolve
character-set-server=utf8
[galera]
wsrep_on=ON
wsrep_causal_reads=ON
wsrep_provider_options="gcache.size=1G"
wsrep_certify_nonPK=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_name=My-Cluster
wsrep_cluster_address="gcomm://192.168.159.45,192.168.159.46,192.168.159.47"
wsrep_node_name=node2
wsrep_node_address=192.168.159.46
wsrep_slave_threads=1
wsrep_sst_method=mariabackup
wsrep_sst_auth='root:123456'
default_storage_engine=InnoDB
log-bin=/data/mysql-bin
log_slave_updates=1
binlog_format=row
query_cache_size=0
innodb_autoinc_lock_mode=2
innodb_flush_log_at_trx_commit=0
innodb_buffer_pool_size=128M
节点3
$ vim /etc/my.cnf.d/server.cnf
#
[mysqld]
server_id=2
datadir=/data
user=mysql
skip-external-locking
skip-name-resolve
character-set-server=utf8
[galera]
wsrep_on=ON
wsrep_causal_reads=ON
wsrep_provider_options="gcache.size=1G"
wsrep_certify_nonPK=ON
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_name=My-Cluster
wsrep_cluster_address="gcomm://192.168.159.45,192.168.159.46,192.168.159.47"
wsrep_node_name=node3
wsrep_node_address=192.168.159.47
wsrep_slave_threads=1
wsrep_sst_method=mariabackup
wsrep_sst_auth='root:123456'
default_storage_engine=InnoDB
log-bin=/data/mysql-bin
log_slave_updates=1
binlog_format=row
query_cache_size=0
innodb_autoinc_lock_mode=2
innodb_flush_log_at_trx_commit=0
innodb_buffer_pool_size=128M
3、启动服务
在node1上面初始化数据库
$ mysql_install_db --defaults-file=/etc/my.cnf.d/server.cnf \
--user=mysql
重点:集群初始化第一个节点有两个方法,自选一个即可。
方法一:在node1上通过galera自带的命令启动(其他节点正常启动即可)
$ galera_new_cluster
方法二:也可以使用传统的bootstrap启动,命令如下(第一个启动的节点需要使用--wsrep-new-cluster参数,其他节点正常启动即可)
$ mysqld_safe --defaults-file=/etc/my.cnf.d/server.cnf \
--user=mysql \
--wsrep-new-cluster &
在node1配置root密码与安全设置
$ mysql_secure_installation
完成以上配置后可以登录node1节点的mariadb数据库查看wsrep集群状态了
$ mysql -uroot -p
#
#查看集群状态
MariaDb [(none)]> SHOW STATUS LIKE 'wsrep_ready';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wsrep_ready | ON |
+---------------+-------+
1 row in set (0.00 sec)
#查看集群的节点数量
MariaDb [(none)]> SHOW STATUS LIKE 'wsrep_cluster_size';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| wsrep_cluster_size | 1 |
+--------------------+-------+
1 row in set (0.00 sec)
#查看集群现有的节点ip地址
MariaDb [(none)]> SHOW STATUS LIKE 'wsrep_incoming_addresses';
+--------------------------+----------------------+
| Variable_name | Value |
+--------------------------+----------------------+
| wsrep_incoming_addresses | 192.168.159.45:3306 |
+--------------------------+----------------------+
1 row in set (0.00 sec)
#查看集群所有信息
MariaDb [(none)]> SHOW STATUS LIKE 'wsrep%';
...省略...
61 rows in set (0.00 sec)
使用以下命令启动另外两个节点(无需使用mysql_install_db初始化)
$ systemctl start mariadb.service
检查/data文件夹发现里面的文件已经同步过来了。
三、集群测试
1、同步测试
在node1测试新建数据库,并插入新数据
MariaDB [(none)]> CREATE DATABASE test_db;
Query OK, 1 row affected (0.02 sec)
MariaDB [(none)]> USE test_db
MariaDB [(none)]> CREATE TABLE test_tbl(id int,name varchar(20),age tinyint);
MariaDB [(none)]> INSERT INTO test_tbl VALUES(1,'Gordon luo','30');
MariaDB [test_db]> SELECT * FROM test_tbl;
+------+------------+------+
| id | name | age |
+------+------------+------+
| 1 | Gordon luo | 30 |
+------+------------+------+
1 row in set (0.00 sec)
登录到node2查看刚刚生成的库与表。
MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test_db |
+--------------------+
4 rows in set (0.00 sec)
MariaDB [(none)]> SELECT * FROM test_db.test_tbl;
+------+------------+------+
| id | name | age |
+------+------------+------+
| 1 | Gordon luo | 30 |
+------+------------+------+
1 row in set (0.00 sec)
2、单节点故障测试
关闭node1的服务
$ mysqladmin -uroot -p 'shutdown'
登录node3查看集群的现有状态
MariaDb [(none)]> SHOW STATUS LIKE 'wsrep%';
+------------------------------+-----------------------------------------+
| Variable_name | Value |
+------------------------------+-----------------------------------------+
| wsrep_apply_oooe | 0.000000 |
...省略...
...省略...
| wsrep_cluster_size | 2 |
| wsrep_cluster_state_uuid | 4bf503b6-6fc5-11e9-bf45-33780c78c635 |
| wsrep_cluster_status | Primary |
| wsrep_cluster_weight | 2 |
...省略...
...省略...
| wsrep_gcomm_uuid | a71601fe-6fd5-11e9-81f0-4f3f68f4fb85 |
| wsrep_incoming_addresses | 192.168.159.47:3306,192.168.159.46:3306 |
| wsrep_last_committed | 17 |
...省略...
...省略...
| wsrep_local_state_comment | Donor/Desynced |
| wsrep_local_state_uuid | 4bf503b6-6fc5-11e9-bf45-33780c78c635 |
| wsrep_open_connections | 0 |
| wsrep_open_transactions | 0 |
| wsrep_protocol_version | 9 |
| wsrep_provider_name | Galera |
| wsrep_provider_vendor | Codership Oy
| | wsrep_provider_version | 25.3.26(r3857) |
| wsrep_ready | ON |
| wsrep_received | 8 |
...省略...
...省略...
| wsrep_thread_count | 2 |
+------------------------------+-----------------------------------------+
61 rows in set (0.00 sec)
可以发现node1已经自动被集群移除
| wsrep_incoming_addresses | 192.168.159.47:3306,192.168.159.46:3306 |
重新启动node1的服务,再次查询集群状态,发现node1已加入集群
| wsrep_incoming_addresses | 192.168.159.45:3306,192.168.159.47:3306,192.168.159.46:3306 |
3、停电故障测试
模拟停电,把所有服务器断电关机
现象一:重启节点后,首先需要检查哪个节点的数据是最新的,使用各节点的grastate.dat文件中的seqno值来判断(seqno值最大为最新的)。
$ vim /data/grastate.dat
#
# GALERA saved state
version: 2.1
uuid: 761d847a-6fe4-11e9-ae1b-7ab987ce04dc
seqno: 6
safe_to_bootstrap: 0
找到最新的节点使用以下命令启动服务
$ galera_new_cluster
#其他节点正常启动
$ systemctl start mariadb.service
现象二:重启节点后,各节点的grastate.dat文件中的seqno值为-1时,这时需要检查gvwstate.dat文件中的my_uuid和view_id的值是否相等,相等的话此节点最新
$ vim /data/gvwstate.dat
#
my_uuid: 03de969c-706c-11e9-b753-ab5cd17d5543
#vwbeg
view_id: 3 03de969c-706c-11e9-b753-ab5cd17d5543 3
bootstrap: 0
member: 03de969c-706c-11e9-b753-ab5cd17d5543 0
member: 7e96e944-7078-11e9-b9b9-daf781ab2476 0
member: e7ac171e-705f-11e9-acba-cbe1d72e724a 0
#vwend
找到最新的节点同样使用以下命令启动服务
$ galera_new_cluster
#其他节点正常启动
$ systemctl start mariadb.service
4、脑裂故障测试
假设node1与node2发生网络故障(拔掉网线)
我们登录node3机查看状态,可以发现wsrep_ready状态是OFF
$ mysql -uroot -p
#
MariaDB [(none)]> SHOW STATUS LIKE 'wsrep%';
+------------------------------+-----------------+
| Variable_name | Value |
+------------------------------+-----------------+
...省略...
| wsrep_cluster_size | 1 |
| wsrep_cluster_status | non-Primary |
| wsrep_ready | OFF |
...省略...
+------------------------------+-----------------+
61 rows in set (0.00 sec)
使用查询与插入命令,都有报错
MariaDB [test_db]> SELECT * FROM test_tbl;
ERROR 1047 (08S01): WSREP has not yet prepared node for application use
MariaDB [test_db]> SELECT @@wsrep_node_name;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
MariaDB [test_db]> INSERT INTO test_tbl VALUES(2,'Gordon.Freeman',30);
ERROR 1047 (08S01): WSREP has not yet prepared node for application use
PS:控制台登录没有网络的node1与node2,结果与上面一致。Galera Cluster很好的保护了脑裂情况下的数据安全。
恢复node1的网络后,Galera Cluster集群恢复状态
$ mysql -uroot -p
#
MariaDB [(none)]> SHOW STATUS LIKE 'wsrep%';
+------------------------------+-----------------+
| Variable_name | Value |
+------------------------------+-----------------+
...省略...
| wsrep_cluster_size | 2 |
| wsrep_cluster_status | Primary |
| wsrep_ready | ON |
...省略...
+------------------------------+-----------------+
61 rows in set (0.00 sec)
MariaDB [test_db]> SELECT * FROM test_tbl;
+------+--------+------+
| id | name | age |
+------+--------+------+
| 1 | gordon | 30 |
+------+--------+------+
1 rows in set (0.00 sec)
MariaDB [test_db]> SELECT @@wsrep_node_name;
+-------------------+
| @@wsrep_node_name |
+-------------------+
| node3 |
+-------------------+
1 row in set (0.01 sec)
MariaDB [test_db]> INSERT INTO test_tbl
> VALUES(2,'Gordon.Freeman',30);
Query OK, 1 rows affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
PS:通过上面的测试可以证实3台节点组成的集群,可以在down掉一台节点的情况下继续提供服务。