之所以把MySQL.GTID_EXECUTED表的作用和PREVIOUS GTID EVENT的改变放到一起进行描述是因为它们后面文章探讨的基础。这部分使用到了我自己使用C语言写的原生BINLOG解析工具INFOBIN。
一、GTID EVENT
为什么要先描述什么是GTID EVENT呢?因为后面会用到,实际上在其中核心元素就是一个形如:
31704d8a-da74-11e7-b6bf-52540a7d243:100009
的一个GTID 处于整个事务EVENT中的开始,用于描述这个事务的GTID 是多少,当然在5.7中为了支持MTS其中还封装了LAST_COMMIT/SEQUENCE_NUMBER。那么使用INFOBIN工具查看一个INSERT单条语句完整事务的EVENT包括如下:
>Gtid Event:Pos:234(0Xea) N_pos:299(0X12b) Time:1513135186Event_size:65(bytes) Gtid:31704d8a-da74-11e7-b6bf-52540a7d243:100009last_committed=0sequence_number=1–>Query Event:Pos:299(0X12b) N_Pos:371(0X173) Time:1513135186Event_size:72(bytes) Exe_time:0Use_db:test Statment(35b-trun):BEGIN/*!Trx begin!*/Gno:100009—->MapEvent:Pos371(0X173) N_pos:415(0X19f) Time:1513135186Event_size:44(bytes) TABLE_ID:108DB_NAME:test TABLE_NAME:a Gno:100009——>Insert Event:Pos:415(0X19f) N_pos:455(0X1c7) Time:1513135186Event_size:40(bytes) Dml on table: test.a table_id:108Gno:100009>Xid Event:Pos:455(0X1c7) N_Pos:486(0X1e6) Time:1513135186Event_size:31(bytes) COMMIT;/*!Trx end*/Gno:100009
当然也可以使用MySQLBINLOG进行分析,只是格式稍微不那么友好。
二、GTID_EXECUTED表的作用
这一部分是重点中的重点,也是我以前一直疑惑的,请大家细细品读。
官方文档这样描述GTID_EXECUTED表
BeginningwithMySQL5.7.5, GTIDs are storedina table named gtid_executed,inthe mysqldatabase. A rowinthistable contains,foreach GTID or setofGTIDs that it represents, the UUIDoftheoriginating server, and the starting and ending transaction IDsofthe set;fora row referencing only asingle GTID, these last two values are the same.
也就是说GTID_EXECUTED表是GTID持久化的一个工具,如前文所描述GTID_STATE中的
GET_EXECUTED_GTIDS/GET_LOST_GTIDS/GET_GTIDS_ONLY_IN_TABLE/GET_PREVIOUS_GTIDS_LOGGED这些数据都是存储在内存中的,那么在数据库重启后需要进行初始化,那么这需要读取GTID持久化的介质,我们可以发现GTID_EXECUTED是一个
INNODB表建表语句如下,并且我们可以手动更改它,但是千万不要这么干:
Table: gtid_executedCreate 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=utf8 STATS_PERSISTENT=0
那么在5.7.5以前没有GTID_EXECUTED表不是也没有问题吗?其实除了GTID_EXECUTED表以外我们还有一个GTID持久化的介质那就是BINLOG中的GTID EVENT。所以总结一下GTID持久化介质:
GTID_EXECUTED表
BINLOG中的GTID EVENT
那么既然有了BINLOG的GTID EVENT进行持久化那么为什么还需要GTID_EXECUTED表呢?这实际上就是5.7.5过后的一个优化,我们可以反过来思考在5.6中如果使用了GTID 做从库,从库如果不开启BINLOG并且同时设置LOG_SLAVE_UPDATES=TURE那么从库的执行过的GTID事务是没有办法持久化的。我们来一段5.6官方文档对于搭建GTID从库的其中一步:
Step3: Restart both serverswithGTIDs enabled. To enable binary loggingwithglobaltransaction identifiers, each server must be startedwithGTID mode, binary logging, slave updatelogging enabled, andwithstatements that are unsafeforGTID-based replication disabled. In addition,you should prevent unwanted or accidental updatesfrombeing performed on either server by startingbothinread-only mode. This means that both servers must be startedwith(at least) the options showninthe following invocationofmysqld_safe:shell> mysqld_safe –gtid_mode=ON –log-bin –log-slave-updates –enforce-gtid-consistency &
开启BINLOG同时设置设置LOG_SLAVE_UPDATES=TURE必然造成一个问题,实际上从库很多时候我们是不需要做级联SLAVE,设置LOG_SLAVE_UPDATES=TURE会造成需要额外的空间和性能开销。自然这种情况下我们需要另外的一种GTID持久化介质,而并不是BINLOG中的GTID EVENT。为了解决这个问题,5.7中GTID_EXECUTED表应运而生了。然而GTID_EXECUTED表是否需要实时更新呢?显然在slave端不开启BINLOG或者开启BINLOG不设置LOG_SLAVE_UPDATES=TURE的情况下它需要实时更新,因为I/O THREAD执行过得GTID是必须持久化的,而在主库上因为有BINLOG的GTID EVENT的存在他是不需要实时更新的,这样不同的对待方式也能够减轻负担提高性能。
阅读原文