MySQL主从复制(4)GTID主从复制与运维管理教程
一、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
7、在从库执行show slave status命令查看事务ID是否与主库一致,Retrieved_Gtid_Set表示从库已经接受到的GTID信息;Executed_Gtid_Set表示从库已经应用了的GTID信息
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信息。
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;
评论