首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > Mysql >

MySQL 5.6 全局事务 ID(GTID)兑现原理(一)

2013-01-23 
MySQL 5.6 全局事务 ID(GTID)实现原理(一)Gtid_set? ?| sidno: 1 | - Interval (1, 5) ? - Interval (11

MySQL 5.6 全局事务 ID(GTID)实现原理(一)
Gtid_set? ?| sidno: 1 | -> Interval (1, 5) ? -> Interval (11, 18)? ?| sidno: 2 | -> Interval (1, 27) -> Interval (29, 115) -> Interval (117, 129)? ?| sidno: 3 | -> Interval (1, 154)?Gtid_set 的结构是一个以 sidno 为序号的数组(同样的,这里允许我先忽略什么是 sidno 这个挠头的问题),每个数组元素都指向一条 Interval 组成的链表,链表中的每个 Interval 用来存放一组事务 ID(gno)的区间,例如 (1,5)。?假设上文中 uuid:3E11FA47-71CA-11E1-9E33-C80AA9429562 对应的 sidno 为 1,那么下面的 GTIDs:?3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5??可以用 Gtid_set 表示为:?Gtid_set? ?| sidno: 1 | -> Interval(1, 5)?MySQL 5.6 引入 Gtid_set 数据结构的目的是为了轻量级的记录大量的连续全局事务 ID,比如已经在 Slave 上执行的全局事务 ID, 或者主库上正在运行的全局事务 ID。这些集合往往包含海量的全局事务 ID。?当 transaction_id / gno 保持连续,Gtid_set 可以在常数时间内判断一个 GTID 是否包含在集合内。这很容易用来检查一个 GTID 是否已经执行过,因此可以用在防止 MySQL 事务在同一个 Slave 上重复执行这类场景。?Gtid_set 也支持一些常见的集合操作,比如检查另一个 Gtid_set 是否子集:is_subset,比如两组 Gtid_set 做交集:intersection。这些方法在根据 GTIDs 自动查找主备复制位点,进行自适应主备切换时有用到。?有个值得一提的细节是,Gtid_set 为了减少链表导致的内存碎片,所有的 Interval 对象都是用 chunk 方式分配的,chunk 大小为 8 * sizeof(Interval)。?这里解释一下 sidno?为减少在索引里保存 128 位 server_uuid 的消耗,Gtid_set 使用 int32 类型的 sidno 代替 server_uuid 作为 Interval 链表的索引。因此,MySQL 需要另一个数据结构在 128 位的 server_uuid 与 32 位的 sidno 之间建立映射,这个结构叫 Sid_map:(代码路径:mysql-5.6.9-rc\sql\rpl_gtid.h, 467 line)?Sid_map := hash_map(sid => sidno)?它基本上就是一个 server_uuid 到 sidno 的 hash_map, ?并且负责顺序产生 sidno:第一个放入 Sid_map 的 sidno 为 1,第二个 sidno 为 2 ...... 注意,生成的 sidno 是临时性的,在 Sid_map 被释放或者 MySQL 实例重启后又会重新分配。?在创建 Gtid_set 时,MySQL 会调用 ensure_sidno() 方法保证 array 内有足够的空间容纳 Sid_map 中所有分配的 sidno。?因为 Sid_map 是一个读多写少的数据结构(显然,只有 MySQL 集群增加或者更换实例时,server_uuid 才会增加),MySQL 用一个读写锁来保护 Sid_map,每当 Gtid_set 在查 Sid_map 时加读锁;每当 Gtid_set 找到新的 server_uuid 需要分配 sidno 时,加写锁。?基本上,MySQL 5.6 所有的 server_uuid 都通过一个全局变量 global_sid_map 来映射。相应的,也有一个全局锁 global_sid_lock 在保护这个 Sid_map。这些代码在 mysqld.cc 的 gtid_server_init 方法里可以找到。(代码路径:mysql-5.6.9-rc\sql\mysqld.cc, 1719 line)?最后介绍一下 Gtid_state?现在,MySQL 5.6 有了记录全局事务 ID 的数据结构 Gtid_set,又维持了一个全局 Sid_map 来映射 server_uuid 与 sidno,下面我们可以开始接触 MySQL 全局事务 ID 的核心数据?Gtid_state 了:?Gtid_state := (logged_gtids, lost_gtids, owned_gtids)?全局事务状态 Gtid_state 在 MySQL 5.6 内只有唯一一个实例,目的是存储三组全局事务 ID 的集合,每个集合的功能我会在下一篇博客阐述:?+---------------+-------------------------+| 名称 ? ? ? ? ? ? ? ?| 功能 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|+---------------+-------------------------+| logged_gtids | 写入到 binlog 的全局事务 ID 集合。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|+---------------+-------------------------+| ? ? ? lost_gtids | 已经从 binlog 删除的全局事务 ID?集合。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? |+---------------+-------------------------+| ?owned_gtids | 正在执行的全局事务 ID 与 MySQL 线程 ID 的集合 ? ? ? ? ? ? ? |+---------------+-------------------------+?注:owned_gtids 变量的类型是 Owned_gtids, 它基本上可以看作一个 Gtid (sidno, gno) 到 owner_thread_id 的 hash_map:?Owned_gtids := array(sidno => hash_map(Node))?Node := (gno, owner_thread_id)??其中 gno 是 Gtid 中的事务 ID。?(未完待续)

?

热点排行