日期:2014-05-16  浏览次数:20701 次

MySQL 5.6 全局事务 ID(GTID)实现原理(三)

这是 MySQL 5.6 全局事务 ID(GTID) 系列的第三篇博客。

?
在之前的两篇博客中,第一篇? 介绍了全局事务 ID 的定义与数据结构。第二篇? 介绍了 MySQL 5.6 新增的全局事务状态(Gtid_state)。
?
这里准备介绍的是全局事务 ID 如何参与 MySQL 的主备复制流程。
?
MySQL 5.6 引入全局事务 ID 的首要目的,是保证 Slave 在复制的时候不会重复执行相同的事务操作;其次,是用全局事务 IDs 代替由文件名和物理偏移量组成的复制位点,定位 Slave 需要复制的 binlog 内容。
?
因此,MySQL 必须在写 binlog 时记录每个事务的全局 GTID,保证 Master / Slave 可以根据这些 GTID 忽略或者执行相应的事务。在实现上,MySQL 没有修改旧的 binlog 事件,而是新增了两类事件:
?
+----------------------------+----------------------------------------+
| 名称 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| 功能 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
+----------------------------+----------------------------------------+
| Previous_gtids_log_event | 该事件之前的全局事务 ID 集合。 ? ? ? ? ?|
+----------------------------+----------------------------------------+
| ? ? ? ? ? ? ? ? ?Gtid_log_event | 标记之后的事务对应的全局事务 ID。 ? ?|
+----------------------------+----------------------------------------+
?
Gtid_log_event
?
在?MySQL 5.6 的 binlog 文件中,每个事务的开始不是 "BEGIN" ,而是 Gtid_log_event 事件:
?
(图片来源:MySQL_Innovation_Day_Replication_HA.pdf?)
?
它里面只包含一条 GTID,记录结构如下:
?
Gtid_log_event := (commit_flag, sid,?gno) ? // commit_flag 目前总是 true
?
里面 sid 就是产生该事务的 server_uuid,gno 是顺序编号的 transaction_id。
?
把 Gtid 记录在事务的开头是为了便于 MySQL 过滤 binlog:检查到某个 Gtid 不需要时,可以直接忽略后面的整段事务。