`
in355hz
  • 浏览: 230295 次
社区版块
存档分类
最新评论

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

阅读更多

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 的关联(这需要解释一些另外复杂的东西)。gno 是 64 位整数,等同于上面提到的 transaction_id。
 
在 MySQL 内部更常见的数据类型是 Gtid_set,表示一组 GTID 的集合,在官方文档中通常写成 GTIDs。例如,下面就是一个 GTIDs:
 
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
 
表示在 MySQL 实例 3E11FA47-71CA-11E1-9E33-C80AA9429562 上执行的第 1 到第 5 个数据库事务。
 
复杂一点的是:如果这组 GTIDs 来自不同的 source_id,各组 source_id 之间用逗号分隔;如果事务序号有多个范围区间,各组范围之间用冒号分隔,例如:
 
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5:11-18,
2C256447-3F0D-431B-9A12-575BB20C1507:1-27
 
GDITs 和 Gtid_set
 
在 MySQL 5.6 源码里,Gtid_set 是个较为复杂的数据结构,基本结构可以用伪码表示成:(代码路径:mysql-5.6.9-rc\sql\rpl_gtid.h, 842 line) 
 
Gtid_set := array( sidno => link_list(Interval) )
 
Interval := (start, end)
 
用示意图表示应该是这样:
 
 
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。
 
(未完待续)

 

0
1
分享到:
评论

相关推荐

    MySQL5.6-Replicate架构图(高清)

    官方文档:http://dev.mysql.com/doc/refman/5.6/en/replication-gtids.html在这篇文档里,我们可以知道GTID(全局事务 ID) 的官方定义是:GTID实际上是由UUID+TID组成的,其中UUID是一个MySQL实例的唯一标识,TID...

    mysql5.6免安装版

    6. **复制优化**:引入了GTID(Global Transaction Identifier)全局事务ID,简化了复制设置和故障恢复,同时也提高了复制的可管理性和可靠性。 7. **监控和性能分析**:新的Performance Schema提供了一套全面的...

    mysql 5.6 32位

    - **GTID(Global Transaction Identifier)**:5.6版本引入了全局事务ID,简化了复制管理,使得追踪和恢复事务更加容易。 4. **优化器改进**: - **Query Optimizer Enhancements**:包括统计信息的自动更新和更...

    mysql5.6.zip精简解压版

    6. **复制功能增强**:支持半同步复制,确保主库和从库之间的数据一致性,同时增加了GTID(Global Transaction Identifier)全局事务ID,简化了复制的管理和故障恢复。 7. **更好的监控和诊断工具**:MySQL 5.6提供...

    MySQL Server 5.6.zip

    8. **GTID(Global Transaction Identifier)**:MySQL 5.6开始引入全局事务ID,用于追踪和管理复制中的事务,简化了复制的管理和故障恢复过程。 9. **内存管理优化**:内存分配和管理的改进减少了内存碎片,提高了...

    mysql5.6说明文档

    9. **增强的复制选项**:如GTID(全局事务标识符)复制,简化了复制设置和故障恢复,通过唯一的事务ID跟踪复制。 10. **在线DDL(数据定义语言)操作**:MySQL 5.6支持部分DDL操作在线进行,如添加或删除索引,减少...

    MySQL 5.6 GTID新特性实践

    MySQL 5.6 引入的 GTID(Global Transaction ID)特性是一项重大的进步,它极大地简化了数据库复制和故障转移的过程。GTID 是一个全局唯一标识,用于标记已提交的事务,由两部分组成:UUID 和 TID。UUID 是每个 ...

    mysql5.6ocp 1z0-883.docx

    - 表示该复制配置使用了GTID(全局事务标识符)模式,并且已经接收到了ID为1到8的事务。 **解题思路** 当出现Duplicate Entry错误时,通常是因为从服务器上的数据与主服务器不同步或者存在人为修改。在这种情况下...

    mysql-5.6.47-winx64

    5. **GTID(Global Transaction Identifier)**:全局事务标识符是一种自动分配的唯一ID,用于跟踪和管理复制中的事务。这简化了复制拓扑的管理和故障恢复。 6. **Query Cache优化**:虽然MySQL 8.0中移除了Query ...

    05_数据库代理——企业博客MySQL 5.7 基于GTID的并行MTS多级主从 Multisource Crash safe半

    GTID是MySQL 5.6及以上版本引入的一种全局事务标识符,它为每个事务分配一个唯一的ID,使得在主从复制过程中,无需手动跟踪二进制日志的位置,简化了复制过程,并增强了故障恢复的能力。在本项目中,GTID被用于...

    mysql_56_GTID_in_a_nutshell

    在深入探讨之前,我们先明确一下 **GTID** 的定义:**GTID**(Global Transaction Identifier)是MySQL 5.6中引入的一个用于标识分布式环境下唯一事务的标识符。它由两部分组成: 1. **SID (Server ID)**:这是一个...

    MySQL——特别响、非常近.pdf

    在复制功能上,MySQL 5.6引入了全局事务ID(GTID)这一重大改进。GTID使得在复制集群中,各个数据库节点可以通过GTID追踪需要复制的事务,即使某个节点故障,其他节点也能无缝接管复制工作,极大地增强了系统的高...

    MySQL GTID 与半同步复制1

    MySQL的全局事务标识符(Global Transaction Identifier, GTID)是一种在MySQL 5.6版本引入的高级复制特性,旨在解决传统基于binlog位置的复制方式存在的问题,如故障恢复复杂、幂等问题。GTID能够唯一标识数据库中...

    MySQL主从复制原理 _ 异步复制 _ 半同步复制 _ GTID复制.pdf

    全局事务标识符(Global Transaction Identifier,GTID)是MySQL 5.6及更高版本引入的一种高级复制机制。每个在主库上提交的事务都会分配一个唯一的GTID,从库在复制时基于GTID而不是位置(binlog position)进行。...

    MySQL 5.6 & 5.7最优配置文件模板(my.ini)

    `log_bin`开启二进制日志,`gtid_mode`和`enforce_gtid_consistency`启用GTID(全局事务标识符)以确保复制一致性。 9. **innodb settings**: InnoDB存储引擎的配置,对性能影响巨大: - `innodb_page_size`: 默认...

    Mysql GTID Mha配置方法

    标题所指的知识点是“Mysql GTID Mha配置方法”,它涵盖了在MySQL数据库环境中,使用全局事务标识符(GTID)和主从高可用性(MHA)的配置步骤。GTID是MySQL 5.6以上版本引入的一种新特性,可以简化复制环境的配置和...

    manual56:MySQL 5.6手册翻译

    - **GTID(全局事务标识符)**:引入全局唯一的事务ID,简化复制管理,支持更灵活的故障恢复和主从切换。 5. **性能监控与分析**: - **Performance Schema**:提供了一个完整的性能监控框架,能够深入分析SQL...

    MYSQL基于GTID的复制

    MySQL的全局事务ID(GTID)复制是一种高效且可靠的数据库复制解决方案,自MySQL 5.6版本开始引入。GTID复制解决了基于日志位置的传统复制方式存在的问题,如因错误指定二进制日志偏移量导致的数据不一致。GTID确保了...

Global site tag (gtag.js) - Google Analytics