实验环境

此次实验的环境如下

  • MySQL 5.7.25

  • Redhat 6.10

  • 操作系统账号:mysql

  • 数据库复制账号:repl

  • 复制格式:基于行的复制

IP地址 主从关系 复制账号 复制格式
11.12.14.29 主库 repl Row-Based
11.12.14.30 从库(半同步) repl Row-Based
11.12.14.31 从库(异步) repl Row-Based

通过前面的介绍我们知道MySQL的复制有两种方法

  • 基于二进制日志文件位置
  • 基于GTID

上一节的内容为GTID的生命周期,提到了gtid_next系统变量,当备库接收到主库的GTID事务后,会将gtid_next变量设为该GTID作为下一个需要执行的事务

接下来具体说下这个系统变量

1. gtid_next

我们知道一个新的事务在提交后会被分配一个新的GTID,当该事务在从库上被应用时会保留主库上的GTID

1.png

我们可以通过设定gtid_next 的值来改变这种行为

  • 1.1 AUTOMATIC

    当设置为AUTOMATIC时(默认值)时,系统会自动分配一个GTID,如果事务回滚或者没有写入到二进制文件时则不会分配

  • 1.2 具体的GTID值

    我们可以设置该变量为一个具体的有效的GTID,这时服务器会将该GTID分配给下一个事务,就算该事务没有被写入二进制日志或者为空事务,该GTID也会被分配并加入到gtid_executed变量中

这里需要注意的是,如果该变量值不为AUTOMATIC,我们需要手动的为每个事务指定GTID,否则该事务会失败,你可以将其改为AUTOMATIC,让服务器自动分配,具体可看下面的实验

2. gtid_purged

在gtid_purged系统变量里面的GTID集合是那些已经在服务器上提交的,但已经不存在与二进制日志文件中了

2.png

gtid_purged 是gtid_executed的一个子集

存在于该变量里面的GTID主要有如下种类

  • 从库如果禁用二进制日志功能的话,提交的事务会被记录进去

  • 该事务所在的二进制日志文件被清理,可能是人为清理的也可能是自动清理的,自动清理由expire_logs_days参数控制

  • 通过设置GLOBAL.gtid_purged变量手动添加进去的,gtid_purged的值,则该GTID也会被写入到gtid_executed变量里面,即不会被执行,注意只有当gtid_executed为空时才可以手动添加

2.1 mysqldump中的gtid_purged

还记得在mysqldump专题中讲到需要加上--set-gtid-purged=off参数吗,如果不加上的话会在文件中出现set gtid_purged信息

8.png

如果这时候用他来还原的话,如果需要还原的库gtid_executed有信息的话是会还原失败的

9.png

这时可以通过reset master清除掉gtid_executed信息即可

3. 关于gtid_next的实验

这个实验我们模拟手工设置gtid_next的值,注意该变量是会话级别的

首先查看现在的执行过的GTID值

3.png

之后手动设置,首先我们设置为已经执行过的GTID

SET @@SESSION.GTID_NEXT= 'e99ae99a-811d-11e9-9ca2-0050568cef02:9';

会发现执行成功了,但是并没有新增,说明相同的GTID会被忽略

4.png

这时我们讲其设为未执行过的GTID,这里我们跳过10和11两个编号

SET @@SESSION.GTID_NEXT= 'e99ae99a-811d-11e9-9ca2-0050568cef02:12;
5.png

会发现执行成功并且新增了一行

而且gtid_executed显示的GTID集为1-9:12,有GAP

接下来我们我们试试不设置gtid_next的值看能不能执行成功

6.png

会发现报错了,说明我们需要手动设置

最后我们讲值设为自动的

SET @@SESSION.GTID_NEXT='AUTOMATIC';

之后插入几行,发现GTID的GAP补回来了

7.png

4. 参考资料

本专题内容翻译自官方文档并结合自己的环境

https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-lifecycle.html