0%

MySQL5.6和5.7版本中GTID的不同

前言

这是一篇旧文,之前做项目时遇到的问题,通过查阅相关资料和代码整理而来。本文不会介绍GTID的用法及配置,相关资料网上有一大堆,可自行查阅,主要是为了说明MySQL的GTID在5.6和5.7两个大版本之间的差异,这方面的介绍除了官方文档中有一些介绍外,其他资料到还不多。希望可以让你对GTID的了解更深入一些。

两个版本的GTID差异

配置要求不同

开启GTID复制时,一般涉及这4个配置:

  • gtid_mode=ON
  • log_bin=ON
  • log-slave-updates=ON
  • enforce-gtid-consistency

它们的作用分别表示:是否开启GTID模式、是否开启Binlog文件、slave日志中是否记录SQL线程的更新、是否拒绝可能导致GTID不一致的SQL语句;

在mysql5.6中,如果要使用GTID复制,这四个配置必须全都要启用;但是在mysql5.7中,在使用GTID时,log_binlog-slave-updates两个配置不再是强制开启的(Why?)。不过一般情况下,为了做高可用切换,我们还是会默认开启log_binlog-slave-updates

GTID保存逻辑不同

使用mysql时,假设我们开启了GTID,那么我们查看GTID的方式可以为:

  • show master status
  • show slave status
  • select @@global.gtid_executed

在mysql 5.6中,Executed_Gtid_Setglobal.gtid_executed的取值是相同的,他们都来自于binlog中GTID的集合。具体过程是这样的:

  1. 每次启动的时候:
    • 首先,从最新binlog中读取Previous_gtids_log_event的gtid列表,加入logged_gtids集合中;
    • 其次,从最新binlog中读取所有的Gtid_log_event的gtid,加入到logged_gtids集合中;
  2. 启动之后,后续每个执行的事务所生成的gtid也都会更新到logged_gtids集合中;

总结就是:在MySQL5.6中,Executed_Gtid_Set是在mysqld启动时从最新的binlog中加载的。现在回头来看开启GTID的时候为什么要开启log_bin参数?因为Executed_Gtid_Set是保存在binlog中的,启动的实话需要加载GTID信息,所以必须要开启binlog。

这里再对照mysql源码看下上面的说明。

  • show master status

5.6 show master status

  • select @@global.gtid_executed

5.6 select @@global.gtid_executed

因此,如果启动的时候binlog被清空了,则Executed_Gtid_Set显示为空,后续执行的事务会从事务编号为1的GTID重新开始。读者可自行验证。

下面我们再看下在mysql 5.7中的行为。
首先,5.7中引入了一个新的系统表mysql.gtid_executed, 用于保存已经执行的事务的GTID集合。具体的逻辑为:

  1. 当binlog未开启时,每个执行事务的GTID都会保存在该表中。此时,会启用一个新的GTID压缩线程对该表进行定时压缩,压缩的频率可以通过参数gtid_executed_compression_period来控制(该参数意思是每执行gtid_executed_compression_period个事务执行一次压缩);当使用主从复制时,这种情况只能用于slave上,master上是必须要开启binlog的;
  2. 当binlog开启时,每当binlog轮转或者server正常shutdown时,上一个binlog中的所有GTID集合(包括Previous_gtids_log_event)会记录到该表中;但是,当server非正常关闭时,当前binlog中的GTID并未保存到mysql.gtid_executed表中,在server重启执行recovery时会将这部分GTID保存到mysql.gtid_executed表中;同时注意,开启binlog时,不会启用binlog压缩,参数gtid_executed_compression_period不起作用;

其次,Executed_Gtid_Set变量的值以及global.gtid_executed的值,不再从binlog中读取,而是从系统表mysql.gtid_executed中获取,见下图mysql5.7.18源码实现:

  • show master status

5.7 show master status

  • select @@global.gtid_executed

5.7 select @@global.gtid_executed

  • 函数get_executed_gtids(),注意函数注释

5.7 get_executed_gtids

因此,在mysql 5.7中,开启GTID不再强制要求开启binlog,只有当需要做主从复制中的master时,才必须开启binlog(为了保证高可用时的主从切换,还是建议同时开启主从上的binlog)。但是,如果非正常shutdown后,在启动的时候binlog被清空了,5.7中的Executed_Gtid_Set不会显示为空,而是最后一个binlog的Previous_gtids,相比5.6版本,这缺失的不是全部的GTID,而是最后一个binlog中的gtid_event

总结

总体而言,相比5.6版本,5.7版本对GTID的改进,减少了GTID的使用限制,同时也加强了GTID信息的持久化。不知道在8.0版本中,在GTID方面又有哪些变化,还没来得及看。

参考

如果对您有帮助