MySQL5.7新增表mysql.gtid_executed

MySQL5.6主从,从库获取gtid_executed

在MySQL5.6的时候,主从复制开启了GTID,在slave执行show slave status \G的时候可以获取得到当前执行的GTID的集合信息。在MySQL5.6的时候这个值并不是持久化到文件或者数据库表中的,而是每次在slave重启的时候从最后一个binlog文件的末尾读取写入内存中去的。那么这个样子就会造成一个问题,在从库没有开启log_slave_updates这个参数的时候或者说维护人员不小心将binlog文件给删除了之后,那么slave重启之后就会获取不到gtid_executed的值,那么主从环境就会挂掉。

并且还需要注意的一点就是,就算我们开启了log_slave_updates这个参数,将所有来自于master的事务在本地回放的时候写入slave本地的binlog中去的话,那么不可避免会造成磁盘IO和磁盘空间资源的浪费。

MySQL5.7新增的mysql.gtid_executed

在MySQL5.7的时候则将gtid_executed的信息持久化到了表中,这个表就是mysql.gtid_executed表:

root@mysqldb 11:03:  [(none)]> 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

执行SQL可以看到这个表的一些具体信息:

root@mysqldb 11:04:  [(none)]> select * from mysql.gtid_executed ;
+--------------------------------------+----------------+--------------+
| source_uuid                          | interval_start | interval_end |
+--------------------------------------+----------------+--------------+
| 4725234c-1acc-11e8-9ff9-000c29a80f41 |              1 |          781 |
| 4725234c-1acc-11e8-9ff9-000c29a80f41 |            989 |         1011 |
| 4cf4a087-1ba3-11e8-92f6-000c2920ceb4 |              1 |         2239 |
+--------------------------------------+----------------+--------------+
3 rows in set (0.00 sec)

新增mysql.gtid_executed表之后,slave重启之后可以直接从这个表中获取信息。需要注意的是mysql.gtid_executed是在主从服务器上面都会进行更新的,而表slave_relay_log_info仅仅只是在从服务器进行更新的。

可以看到上述的表mysql.gtid_executed并没有记录每个事务的GTID的值,而是记录了GTID的起始值和末尾值,这个是因为为了避免这个表的记录疯狂的增长,所以MySQL5.7引入了一个新的进程进行专门的压缩,并且有专门的参数来设置这个压缩比。

root@mysqldb 11:58:  [(none)]> select thread_id,thread_os_id,name,processlist_command,processlist_state from performance_schema.threads where name like '%compress%';
+-----------+--------------+--------------------------------+---------------------+-------------------+
| thread_id | thread_os_id | name                           | processlist_command | processlist_state |
+-----------+--------------+--------------------------------+---------------------+-------------------+
|        27 |        23839 | thread/sql/compress_gtid_table | Daemon              | Suspending        |
+-----------+--------------+--------------------------------+---------------------+-------------------+
1 row in set (0.00 sec)

root@mysqldb 11:59:  [(none)]> show global variables like 'gtid_executed_compression_period';
+----------------------------------+-------+
| Variable_name                    | Value |
+----------------------------------+-------+
| gtid_executed_compression_period | 1000  |
+----------------------------------+-------+
1 row in set (0.01 sec)

root@mysqldb 11:59:  [(none)]>

还有一点需要我们注意的:mysql.gtid_executed的记录方式是和从库是否开启记录二进制日志是有很大的关系的。若是slave开启了二进制日志,则该表只会在二进制日志切割的时候或者MySQL正常关闭进行更新,否则的话就会进行实时的更新。还有需要注意的一点就是,在MySQL异常关闭的时候GTID的信息是不会记录到这个表中的,在MySQL恢复的时候会从binlog中记录写入这个表中的。

当binlog开启的时候,并且exectued_gtids_compression_period值未使用的时候,MySQL的binlog轮换也会引起mysql.gtid_executed表的自动压缩。