MySQL主从复制(4)GTID主从复制与运维管理教程

TangLu MySQL 2021-03-15 7018 0

一、MySQL GTID特性

MySQL 5.6 开始支持全局事务标识(简称GTID),它是 InnoDB 引擎下为每个事务记录的全局唯一编号,每当有事务导致数据变化就会产生一个对应的GTID(每一个DDL语句都有一个GTID,对于DML语句,从begin开始到commit结束才算一个GTID),GTID末位的数字呈现递增5.7之后即便没有配置GTID也会存在匿名事务,只不过这个匿名事务不包含GTID信息,不能用于主从复制。GTID拥有全局唯一性和幂等性,一个完整的GTID包含了UUID和GTID两部分,UUID即Server_uuid,用于区分事务来自于集群中哪个节点,MySQL在启动的时候通过读取auto.cnf获取UUID,如果auto.cnf文件丢失则会自动生成新的UUID,如下为GTID示例

# 同一个实例的事务GTID会进行合并,比如来自同一个实例的1-3号事务,会写为1-3。事务之间如果不连续,则用逗号分隔
2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-3
2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-3,11,48-51

因为全局唯一性,GTID可以简化主从复制的维护,配置主从不再需要手动指定Position信息,只需要告知从库当前从哪个GTID开始执行后面的事务即可。在进行主从切换时也更方便,不同节点之间的GTID是连续的,不再和传统模式下存在每个节点binlog position不相同的情况。如果非MGR集群的主从架构出现GTID空洞,比如1-100,200-300这样不连续的事务,需要检查主从数据是否完全一致,如果确定空洞事务是不需要的,可以通过注入空事务的方式把空洞补上。

需要注意启用GTID以后,不再支持create table...select...语句,因为该语句实际是先CREATE TABLE再INSERT会生成2个GTID,违背了GTID下一个事务只有一个GTID的特性。并且也不支持使用CREATE TEMPORARY TABLE临时表相关操作


二、MySQL GTID 相关表与变量

· mysql.gtid_executed

该表存储了GTID信息,数据库实例启动时会读取该表信息并赋值给gtid_executed变量(在MySQL 5.6时期是使用binlog中的GTID_LOG_EVENT来持久化GTID信息的,所以必须配置 log_slave_updates=1 才能使用GTID的主从方式)

· gtid_executed

该变量用于实时查看当前数据库实例已经执行过的GTID集合执行show master status或show slave status时返回的Executed_Gtid_Set的值就来自于该变量

· gtid_purged

该变量记录了已经被删除或丢弃的GTID事务(Binlog过期或人为操作删除都算)。在部署从库的时候通常需要使用set global gtid_purged命令来设置该变量,表示从库不需要再执行这些GTID包含的操作(因为这些事务已经在备份数据中了),否则会因为日志被删除了而导致同步失败


三、MySQL GTID 主从部署过程

1、在所有节点新增GTID相关配置,MySQL 5.7开始支持在线配置GTID,无需重启服务。但是为了确保MySQL能正确处理从匿名事务更改为GTID事务的过程,gtid_mode的值只能按照顺序逐一提升或下降,如可以从OFF_PERMISSIVE逐步升级为ON_PERMISSIVE和OFF,但是不能直接调整为ON,关于GTID在线开启详见https://ywdba.cn/post-647.html

#开启GTID
gtid_mode = on

#强制GTID一致性,开启后如果再去执行一些会导致GTID复制失败的语句会报错,可以避免数据的不一致  
enforce_gtid_consistency = on  

#5.7以后通过gtid_executed表对GTID持久化,所以该参数可以不配置,5.6则依赖binlog进行持久化,必须开启
#log_slave_updates = 1  


2、主库进行授权操作

grant replication slave,replication client on *.* to 'repl'@'192.168.1.110' identified by '123456'


3、从库恢复主库的备份数据,备份数据恢复后需要在从库指定gtid_purged变量信息,这个信息根据备份方式不同查找的路径会有一些不同。如果是mysqldump逻辑备份,在备份文件前50行会有gtid_purged变量,而xtrabackup物理备份的话则会写入到xtrabackup的备份文件中

#通过备份还原数据后通过该命令可以看到从节点和主节点GTID信息是一致的 
show master status \G  

#防止从库读取到错误的gtid_executed变量,执行该命令可以重置变量
reset master;        

#指定从库需要跳过的GTID信息,也就是让从库从该GTID之后开始进行复制
set global gtid_purged='xxxxxxxxxx:1-21';


4、从库指定同步位点信息。由于采用了GTID,所以从库在指定position信息时只用声明从哪个GTID后开始同步即可

change master to master_host='192.168.1.100',master_port=3306,master_user='repl',master_password='123456',master_auto_position=1;
start slave;


5、数据目录下的auto.cnf存放了当前数据库的UUID,每个节点的ID是不能一样的,如果一样会出现主从状态是2个yes,但是数据不同步的情况

show global variables like 'server_uuid' ;


6、主库执行show binlog event命令可以查看当前事务情况,SET开头的行是GTID,下面一行就是具体的SQL

GTID.png


7、在从库执行show slave status命令查看事务ID是否与主库一致,Retrieved_Gtid_Set表示从库已经接受到的GTID信息;Executed_Gtid_Set表示从库已经应用了的GTID信息

企业微信截图_20181010095354.png


8、采用了GTID复制后从库也会产生binlog日志,通过show master logs可以看到与主库是一致的。在从库执行show binlog event in 'master-bin.000001'命令可以查看当前所执行的事务ID位置,正常情况与主库也是一致的


四、GTID模式数据恢复

1、在gtid模式下需要进行数据恢复,第一步也是从binlog找出正确的gtid信息然后导出,解析binlog的过程这里略过,假设已经定位到GTID 101的事务是属于drop table,那么就需要恢复到101之前的最后一个事务,假设为100

mysqlbinlog --include-gtids='yourgtid:1-100' mysql-bin.00001 mysql-bin.00002 mysql-bin.00003 mysql-bin.00004 > /tmp/gtid.sql
#还有--exclude-gtids选项用于排除某个GTID


2、使用mysqlbinlog进行恢复的时候要注意,由于GTID的幂等性,相同的GTID不会再次执行。所以恢复的时候要手动关闭GTID检查或mysqlbinlog命令中加入--skip-gtids的选项,它会将重定向文件中的GTID信息删除掉

#方法1
mysqlbinlog --skip-gtids include-gtids='xxxxxxxxxxx:1-100' mysql-bin.00001 mysql-bin.00002 > /tmp/gtid.sql
#方法2
mysql > set sql_log_bin = 0 ;
mysql > source gtid.sql;


五、GTID模式跳过指定事务

1、和传统主从不同,开启GTID后如果需要跳过一个事务不能再使用sql_slave_skip_counter参数,而是要获得从库执行的最后一个GTID操作。也就是show slave status 中的Retrieved_Gtid_Set信息。企业微信截图_20211008171159.png


2、构建一个或多个空事务

stop slave;
set gtid_next='xxxxxxxxxxxxxxxcb140c:10903292'
begin;
commit;

set gtid_next='xxxxxxxxxx3:4'
begin;
commit;

set gtid_next='automatic';
start slave;


六、GTID模式其他常见故障与处理

· Master_has_purged_require_gtids

主库提前删除了还未同步完成的binlog

#在从库上手动指定二进制日志文件和位置
mysql > stop slave;
mysql > change master to master_host='192.168.1.100',master_user='repl',master_password='123456',master_log_file='master-bin.000005',master_log_pos=526,master_auto_position=0;
mysql > start slave;


· 如果从库未指定relaylog的同时修改了系统主机名,只需要在从库重新执行一次同步

stop slave;
reset slave;
change master to master_host='192.168.1.100',master_port=3306,master_user='repl',master_password='123456',master_auto_position=1;


· Slave has more GTIDs than the master has,using the master's SERVER_UUID

该问题代表从库获取到的GTID超过了主库,比如主库在未指定binlog文件名的同时修改了系统主机名,导致binlog全部被修改,从库就会判断失败;或者主库未配置双1参数时断电,导致从库提前获取到了还未执行的GTID,解决方法如下:

#全在从库执行
stop slave;
reset slave;
reset master;  #从库的binlog已经无效了,所以要执行这个命令清空binlog
change master to master_host='192.168.1.100',master_port=3306,master_user='repl',master_password='123456',master_auto_position=1;


评论