MySQL 5.6版本开启GTID模式,必须打开参数log_slave_updates,
简单来说就是必须在从机上再记录一份二进制日志。这样的无论对性能还是存储的开销,无疑会相应的增大
而MySQL 5.7版本开始无需在GTID模式下启用参数log_slave_updates,其中最重要的原因在于5.7在mysql库下引入了新的表gtid_executed,其表结构如下所示:
mysql> SHOW CREATE TABLE mysql.gtid_executed\G
*************************** 1. row ***************************
Table: gtid_executed
Create Table: CREATE TABLE `gtid_executed` (
`source_uuid` char(36) NOT NULL COMMENT ‘uuid of the source where the transaction was originally executed.‘,
`interval_start` bigint(20) NOT NULL COMMENT ‘First number of interval.‘,
`interval_end` bigint(20) NOT NULL COMMENT ‘Last number of interval.‘,
PRIMARY KEY (`source_uuid`,`interval_start`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 STATS_PERSISTENT=0
1 row in set (0.00 sec)
简单来说,该表会记录当前执行的GTID。列source对应UUID,列interval_start/interval_end表示的是事务号。在MySQL 5.6中必须配置参数log_slave_updates的最重要原因在于当slave重启后,无法得知当前slave已经运行到的GTID位置,因为变量gtid_executed是一个内存值:
mysql> select @@global.gtid_executed\G
*************************** 1. row ***************************
@@global.gtid_executed: 7af7d3ea-933b-11e5-9da7-fa163e30f9a2:1-72054
1 row in set (0.00 sec)
所以MySQL 5.6的处理方法就是启动时扫描最后一个二进制日志,获取当前执行到的GTID位置信息。当然,如果DBA不小心将二进制日志删除了,那么这又会带来灾难性的问题。
因此,MySQL 5.7将gtid_executed这个值给持久化了。采用的技巧与MySQL 5.6处理SQL thread保存位置的方式一样,即将GTID值持久化保存在一张InnoDB表中,并与用户事务一起进行提交,从而实现数据的一致性:
START TRANSACTION;
# user statement
......
INSERT INTO mysql.gtid_executed VALUES (...)
END;
一致不明白上面几句话是怎么意思,今天在 MYSQL 5.7 版本中 把master.info relay-log.info 以及相应的二进制文件都删掉,中继日志文件删掉,mysql重起,看 slave1的 show master status是否受影响,
发现不受影响,start slave 正常从原来的执行事物点上执行, 但在slave1执行 reset master,会清空mysql.gtid_executed 表,说明已经持久化了,MySQL 5.6 版本my.cnf log_slave_updates用于当mysql重起,由于mysql.gtid_executed 在内存没有持久化,重起变量值会清空,MySQL 5.6的处理方法就是启动时扫描最后一个二进制日志,获取当前执行到的GTID位置信息,这样做的坏处是多写一份二进制日志,增加IO成本
若从MySQL服务器启用了二进制日志,则表mysql.gtid_executed的更新仅在二进制rotation时发生,因为发生重启等情况依旧可以通过扫描二进制日志判断得知当前运行的GTID位置。