一、背景介绍
在MySQL5.6之前,主从复制是通过binlog和position实现的,当A主机宕机后,B主机成为新的主节点,此时在C主机上需要使用sql语句:CHANGE MASTER TO MASTER_HOST='xxx', MASTER_LOG_FILE='xxx', MASTER_LOG_POS='xxx';将自己的复制源指向B主机,难点在于,同一个事务在每台机器上的binlog名字和位置都不一样,怎么找到C主机当前同步停止点在B主机上的master_log_file和master_log_pos位置就成了问题
于是MySQL在5.6.2之后产生了GTID,即全局事务ID(global transaction ID),其形式为:DomainID-ServerID-TransactionID,在配置是必须确保每个MySQL服务器的server_id都不相同,同一GTID事务在每个节点上都是相同的。
二、GTID与binlog
需要注意的是Mariadb的gtid配置方式与MySQL不相同,二者之间不兼容。MaraDB在10.0.2之后的版本默认是启用的,即使从服务器使用的是binlog和position进行主从复制,但他仍是采用GTID进行追踪
这就意味着原先的slave配置可以简单的切换到GTID模式
STOP SLAVE;
CHANGE MASTER TO master_host='xxxx', master_port=3306, master_user='xxx',master_password='xxx',master_use_gtid=current_pos;
START SLAVE;
而从GTID模式切换回以前的binlog模式也不复杂
STOP SLAVE;
CHANGE MASTER TO MASTER_HOST='xxx', MASTER_LOG_FILE='xxx', MASTER_LOG_POS='xxx';
START SLAVE;
三、master_use_gtid介绍
master_use_gtid = { slave_pos | current_pos | no }有3种选项:
slave_pos:slave将Master最后一个GTID的position复制到本地,Slave主机可通过gtid_slave_pos变量查看最后一个GTID的position
current_pos:假设有AB两台主机,A是Master,当A故障后,B成为Master,A修复后以Slave的身份重新添加,A之前从没担任过slave角色,所以没有之前复制的GTID号,此时gtid_slave_pos为空,为了能让A能自动添加为Slave,此时就用到该选项。该选项是大多数情况下使用的选项,因为他简单易用同,不必在意服务器之前是Master还是Slave角色。但要注意不要让从服务器在binlog日志中写入事务。
建议在服务器上启用gtid_strict_mode,这样非Master产生的事物将被拒绝。如果从服务器没有开启binlog上面两种方式等价。
no:关闭GTID功能
四、环境及Maradb配置介绍
本次实验采用CentOS7.4,数据库版本为MariaDB-10.2.14,拓扑如下图所示:
本次模拟当A主机故障后C主机将Master主机重新指向B主机,并且当A主机修复后以Slave的身份重新加入集群
三、操作步骤
1.3台服务器安装MariaDB-10.2.14(略)
2.A主机操作
(1)编辑配置文件
[root@host3 ~]# vim /etc/my.cnf.d/server.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
skip_name_resolve=ON
relay_log=mysql-relaylog
relay_log_index=mysql-relaylog
relay_log_purge=OFF
slow_query_log=ON
server-id=10
innodb_file_per_table=ON
binlog_format=ROW
log_bin=mysql-binlog
log_slave_updates=ON
gtid_strict_mode=ON
(2)启动并进入MySQL
[root@host3 ~]# systemctl start mariadb.service
[root@host3 ~]# mysql
(3)创建一个用于主从复制的账号
MariaDB [(none)]> grant replication slave on *.* to 'bak'@'172.16.10.%' identified by 'bakpass';
MariaDB [(none)]> flush privileges;
(4)备份当前数据库并发送给B主机
[root@host3 ~]# mysqldump -uroot --single-transaction --databases=hellodb --masterdata=2 --quick > /tmp/hello.sql
[root@host3 ~]# scp -r /tmp/hellodb.sql root@172.16.10.40:/tmp
(5)之后做任意DML操作,查看当前 gtid_binlog_pos
MariaDB [hellodb]> show global variables like 'gtid%';
+------------------------+---------+
| Variable_name | Value |
+------------------------+---------+
| gtid_binlog_pos | 0-10-40 |
| gtid_binlog_state | 0-10-40 |
| gtid_current_pos | 0-10-40 |
| gtid_domain_id | 0 |
| gtid_ignore_duplicates | OFF |
| gtid_slave_pos | |
| gtid_strict_mode | ON |
+------------------------+---------+
3.B主机操作(以备份形式复制)
(1)编辑配置文件
[root@host4 ~]# vim /etc/my.cnf.d/server.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
skip_name_resolve=ON
relay_log=mysql-relaylog
relay_log_index=mysql-relaylog
relay_log_purge=OFF
slow_query_log=ON
server-id=20
innodb_file_per_table=ON
binlog_format=ROW
log_bin=mysql-binlog
log_slave_updates=ON
gtid_strict_mode=ON
(2)查看备份时A主机的gtid_slave_pos位置
[root@host4 ~]# cat /tmp/hello.sql
(3)登陆MySQL,创建一个用于主从复制的账号
[root@host4 ~]# systemctl start mariadb.service
[root@host4 ~]# mysql
MariaDB [(none)]> grant replication slave on *.* to 'bak'@'172.16.10.%' identified by 'bakpass';
MariaDB [(none)]> flush privileges;
(4)以备份方式还原并同步数据库
MariaDB [(none)]> source /tmp/hellodb.sql;
MariaDB [(none)]> SET GLOBAL gtid_slave_pos = '0-10-38';
MariaDB [(none)]> CHANGE MASTER TO master_host='172.16.10.30', master_port=3306, master_user='bak', master_password='bakpass',master_use_gtid=slave_pos;
MariaDB [(none)]> start slave;
(5)验证效果
MariaDB [hellodb]> show global variables like 'gtid%';
+------------------------+-----------------+
| Variable_name | Value |
+------------------------+-----------------+
| gtid_binlog_pos | 0-10-40 |
| gtid_binlog_state | 0-20-37,0-10-40 |
| gtid_current_pos | 0-10-40 |
| gtid_domain_id | 0 |
| gtid_ignore_duplicates | OFF |
| gtid_slave_pos | 0-10-40 |
| gtid_strict_mode | ON |
+------------------------+-----------------+
可以看到gtid_binlog_pos已经和A主机保持一致,之前导入数据库和创建复制账号所以B主机上gtid_binlog_state有2个值,官方建议开启gtid_strict_mode选项或临时禁用sql_log_bin
4.设置C服务器(以新服务器方式同步)
(1)编辑配置文件(该服务器只作为Slave角色binlog可以不要)
[root@host5 ~]# vim /etc/my.cnf.d/server.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
skip_name_resolve=ON
relay_log=mysql-relaylog
relay_log_index=mysql-relaylog
relay_log_purge=OFF
slow_query_log=ON
server-id=20
innodb_file_per_table=ON
binlog_format=ROW
log_bin=mysql-binlog
log_slave_updates=ON
gtid_strict_mode=ON
(2)启动并进入MySQL
[root@host5 ~]# systemctl start mariadb.service
[root@host5 ~]# mysql
(3)以空服务器进行数据库同步恢复
MariaDB [(none)]> SET GLOBAL gtid_slave_pos = "";
MariaDB [(none)]> CHANGE MASTER TO master_host='172.16.10.30', master_port=3306, master_user='bak', master_password='bakpass',master_use_gtid=current_pos;
MariaDB [(none)]> start slave;
(4)验证效果
MariaDB [(none)]> show global variables like 'gtid%';
+------------------------+---------+
| Variable_name | Value |
+------------------------+---------+
| gtid_binlog_pos | 0-10-40 |
| gtid_binlog_state | 0-10-40 |
| gtid_current_pos | 0-10-40 |
| gtid_domain_id | 0 |
| gtid_ignore_duplicates | OFF |
| gtid_slave_pos | 0-10-40 |
| gtid_strict_mode | ON |
+------------------------+---------+
===================以上完成主从环境搭建=========================
5.停止A主机MySQL服务,模拟故障
[root@host3 ~]# systemctl stop mariadb.service
6.此时将B主机提升为Master主机,并进行操作
MariaDB [hellodb]> stop slave;
MariaDB [hellodb]> show global variables like 'gtid%';
+------------------------+-----------------+
| Variable_name | Value |
+------------------------+-----------------+
| gtid_binlog_pos | 0-10-40 |
| gtid_binlog_state | 0-20-37,0-10-40 |
| gtid_current_pos | 0-10-40 |
| gtid_domain_id | 0 |
| gtid_ignore_duplicates | OFF |
| gtid_slave_pos | 0-10-40 |
| gtid_strict_mode | ON |
+------------------------+-----------------+
MariaDB [hellodb]> delete from students where stuid=21;
MariaDB [hellodb]> show global variables like 'gtid%';
+------------------------+-----------------+
| Variable_name | Value |
+------------------------+-----------------+
| gtid_binlog_pos | 0-20-41 |
| gtid_binlog_state | 0-10-40,0-20-41 |
| gtid_current_pos | 0-20-41 |
| gtid_domain_id | 0 |
| gtid_ignore_duplicates | OFF |
| gtid_slave_pos | 0-10-40 |
| gtid_strict_mode | ON |
+------------------------+-----------------+
7.将C主机的Master有A指向B,并观察变化
MariaDB [(none)]> show global variables like 'gtid%';
+------------------------+---------+
| Variable_name | Value |
+------------------------+---------+
| gtid_binlog_pos | 0-10-40 |
| gtid_binlog_state | 0-10-40 |
| gtid_current_pos | 0-10-40 |
| gtid_domain_id | 0 |
| gtid_ignore_duplicates | OFF |
| gtid_slave_pos | 0-10-40 |
| gtid_strict_mode | ON |
+------------------------+---------+
MariaDB [(none)]> stop slave;
MariaDB [(none)]> CHANGE MASTER TO master_host='172.16.10.40', master_port=3306, master_user='bak', master_password='bakpass',master_use_gtid=current_pos;
MariaDB [(none)]> start slave;
MariaDB [(none)]> show global variables like 'gtid%';
+------------------------+-----------------+
| Variable_name | Value |
+------------------------+-----------------+
| gtid_binlog_pos | 0-20-41 |
| gtid_binlog_state | 0-10-40,0-20-41 |
| gtid_current_pos | 0-20-41 |
| gtid_domain_id | 0 |
| gtid_ignore_duplicates | OFF |
| gtid_slave_pos | 0-20-41 |
| gtid_strict_mode | ON |
+------------------------+-----------------+
此时C主机的gtid_slave_pos已发生改变
MariaDB [(none)]> show variables like 'gtid_slave_pos';
+----------------+---------+
| Variable_name | Value |
+----------------+---------+
| gtid_slave_pos | 0-20-41 |
+----------------+---------+
8.再将A主机以Slave的身份加入集群操作
[root@host3 tmp]# systemctl start mariadb.service
[root@host3 tmp]# mysql
MariaDB [(none)]> CHANGE MASTER TO master_host='172.16.10.40', master_port=3306, master_user='bak', master_password='bakpass',master_use_gtid=current_pos;
MariaDB [(none)]> show variables like 'gtid_slave_pos';
+----------------+---------+
| Variable_name | Value |
+----------------+---------+
| gtid_slave_pos | 0-20-41 |
+----------------+---------+
至此全部操作完成
补充说明:
1.master_use_gtid = { slave_pos | current_pos }具体用哪一种仍不是很明白,文档说current_pos适用于大部分环境,所以后期使用都是用该值。
2.Master和Candidate之间可以采用半同步方式降低数据不一致
3.双主模式下1台采用binlog1台采用GTID可以正常工作