MySQL 5.6 的新特性之一,是加入了全局事务 ID (GTID) 来强化数据库的主备一致性,故障恢复,以及容错能力。但是,有关 GTID 的作用和原理,在?MySQL 官方网站? 的文档库中却很少被提到。
?
随着 MySQL 5.6 的 rc 版本号原来越高(这意味着 MySQL 5.6 向正式发布越来越近),我想要了解这个神秘功能的想法也越来越急迫。因此,在这篇博客里,我打算从有限的文档出发,通过分析 MySQL 源码,逐部了解 MySQL GTID 和它在主备复制中的作用。
?
什么是 GTID?
?
有关全局事务 ID(GTID),容易找到的是这一篇文档:
?
http://dev.mysql.com/doc/refman/5.6/en/replication-gtids.html
?
在这篇文档里,我们可以知道全局事务 ID 的官方定义是:
?
GTID = source_id:transaction_id
?
在 MySQL 5.6 中,每一个 GTID 代表一个数据库事务。在上面的定义中,source_id 表示执行事务的主库 uuid(server_uuid),transaction_id 是一个从 1 开始的自增计数,表示在这个主库上执行的第 n 个事务。MySQL 会保证事务与 GTID 之间的 1 : 1 映射。
?
例如,下面就是一个 GTID:
?
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
?
表示在以 3E11FA47-71CA-11E1-9E33-C80AA9429562 为唯一标示的?MySQL 实例上执行的第 23 个数据库事务。
?
很容易理解,MySQL 只要保证每台数据库的 server_uuid 全局唯一,以及每台数据库生成的 transaction_id 自身唯一,就能保证 GTID 的全局唯一性。
?
那么,什么又是 server_uuid?
?
MySQL 5.6 用 128 位的 server_uuid 代替了原本的 32 位 server_id 的大部分功能。原因很简单,server_id 依赖于 my.cnf 的手工配置,有可能产生冲突 —— 而自动产生 128 位 uuid 的算法可以保证所有的 MySQL uuid 都不会冲突。
?
在首次启动时 MySQL 会调用 generate_server_uuid() 自动生成一个 server_uuid,并且保存到 auto.cnf 文件 —— 这个文件目前存在的唯一目的就是保存 server_uuid。
?
在 MySQL 再次启动时会读取 auto.cnf 文件,继续使用上次生成的 server_uuid。
?
使用 SHOW 命令可以查看 MySQL 实例当前使用的 server_uuid?:
?
SHOW GLOBAL VARIABLES LIKE 'server_uuid';
?
它是一个 MySQL 5.6 global variables,文档链接在这里:?server_uuid?
?
全局唯一的 server_uuid 可以解决由 server_id 配置冲突带来的 MySQL 主备复制的异常终止(BUG?#33815?):
?
在 MySQL 5.6,Slave 向 Master 申请 binlog 时,会首先发送自己的 server_uuid,Master 用 Slave 发送的 server_uuid 代替 server_id (MySQL 5.6 之前的方式)作为 kill_zombie_dump_threads 的参数,终止冲突或者僵死的 BINLOG_DUMP 线程。
?
回过头来,让我们继续了解 GTID:
?
在 MySQL 5.6 源码内部,GTID 的数据结构可以用伪码写成:
(代码路径:mysql-5.6.9-rc\sql\rpl_gtid.h, 754 line)?
?
Gtid := (sidno, gno)
?
其中 sidno 是代表 sid 的 32-bit 序号,sid 是 source_id 或者 server_uuid 的二进制表示 —— 这里我先忽略 sidno 和 sid 的关联(这需要解释一些另外