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

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

阅读更多
前文 MySQL 5.6 全局事务 ID(GTID)实现原理(一)​ 介绍了 MySQL 5.6 全局事务 ID 的定义和相关的数据结构 Gtid_set 与 Sid_map。接下来,这一篇的主要目标是深入了解文章最后提到的全局事务状态 Gtid_state。并且,如果可能 —— 顺便介绍下这些 Gtid_state 在主备复制中的功能:
 
全局事务状态 Gtid_state
 
Gtid_state 是 MySQL 5.6 内的一个全局对象,它的数据结构如下: 
(mysql-5.6.9-rc\sql\rpl_gtid.h,line 2043)
 
Gtid_state := (logged_gtids, lost_gtids, owned_gtids)
 
创建 Gtid_state 的代码可以在 mysqld.cc 的 gtid_server_init 方法里找到。
(代码路径:mysql-5.6.9-rc\sql\mysqld.cc, 1719 line)
 
Gtid_state 的重要性是,它维护三个与全局事务 ID 有关的 MySQL global variables:
 
logged_gtids / `gtid_executed`
 
存储已经执行过,并且记录到 binlog 的全局事务 ID 集合。它对应的 MySQL variable 是 gtid_executed,可以用命令:
 
SHOW GLOBAL VARIABLES LIKE 'gtid_executed'
 
查看数据库上已经执行的全局事务 ID。
 
MySQL 5.6 在开启 --gtid_mode​=ON 后,每当执行完一个事务,就会调用 Gtid_state 的 update_on_flush() 方法,把事务对应的 GTID 写入 logged_gtids。
 
详细一点的过程是这样的:
 
为了防止写入 binlog 的是一组不完整的事务,MySQL 会缓存整个事务的 binlog 内容在 binlog_cache_data 中。如果事务提交,MySQL 会执行一个叫 ordered_commit() 的三阶段提交操作:
(源代码:mysql-5.6.9-rc\sql\binlog.cc,line 6245)
 
第一步:调用 process_flush_stage_queue() 和 flush_io_cache() 将缓存在 binlog_cache_data 中的内容刷出到 binlog 文件。此时,Gtid_state 的 update_on_flush() 调用到,事务对应的 GTID 写入 logged_gtids。
 
第二步:调用 sync_binlog_file() 在 binlog 文件上执行 fsync() 保证内容更新到磁盘。 
 
第三步:调用 process_commit_stage_queue() 执行所有事务提交,在存储引擎上调用 ha_commit_low()。
 
结束后,MySQL 调用 Gtid_state 的 update_on_commit(),从 owned_gtids 里删除完成  commit 的全局事务 ID。
 
与名字相同,logged_gtids 用来判断 MySQL 有没有执行某个事务。例如,在 Master 发送 binlog 时,MySQL 5.6 能够根据 Slave 提供的 logged_gtids 记录,自动过滤 binlog 中不需要执行的事务(请参考新增 COM_BINLOG_DUMP_GTID 协议)。 
 
另外,MySQL 5.6 支持在 START SLAVE 时指定 UNTIL_SQL_BEFORE_GTIDS / UNTIL_SQL_AFTER_GTIDS 条件,让 Slave 执行完所需要的事务后就自动停止复制。这个功能也依赖于 Slave 的 logged_gtids 记录来检查作为条件的 GTIDs 是否满足。
 
lost_gtids / `gtid_purged`
 
记录从 binlog 删除的全局事务 ID 集合。它对应的 MySQL Global variable 是:gtid_purged​ 。
 
每当 MySQL 5.6 调用 purge_logs 删除 binlog 时,会顺带更新 lost_gtids 的内容。这是通过读剩下的 binlog 文件实现的,我会在介绍 GTID 在 binlog 的存储方式时描述。
(源代码:mysql-5.6.9-rc\sql\binlog.cc,line 3754)
 
它的作用是检查 Slave 请求的 Gtids 是否已经被 Master 删除。如果 Master 的 lost_gtids 记录已经不是 Slave 的 logged_gtids 记录的子集,请求的 Slave 会收到代码为 ER_MASTER_HAS_PURGED_REQUIRED_GTIDS 的错误。
 
owned_gtids / `gtid_owned`
 
正在由线程执行的全局事务 ID 集合。它对应的 MySQL variable 是:gtid_owned,而对应​的类型是 Owned_gtids,基本上可以看作一个 Gtid 到 owner_thread_id 的 hash_map 映射:
 
Owned_gtids := array(sidno => hash_map(Node))
 
Node := (gno, owner_thread_id) 
 
其中 gno 是 Gtid 中的事务 ID。
 
在 MySQL 5.6 中,owned_gtids 提供了一个正在执行的事务纪录(以及执行它们的线程 ID)。这份记录是怎么维护的? —— 这与 MySQL 产生 GTID 的过程有关:
 
每个数据库更新都会产生一条 binlog,当一条 binlog 写入 binlog_cache_data 之前,MySQL Master 会调用 generate_automatic_gno() 产生一个 gno —— 事务 ID,详细过程是这样的:
 
首先,generate_automatic_gno  会检查 Gtid_state 中的 logged_gtids 和 owned_gtids,找到一个当前最大的而且没有使用的 gno(Gtid_state 的 get_automatic_gno() 方法),创建出新的 Gtid。
 
然后,MySQL 调用 Gtid_state 的 acquire_ownership(),把新的 Gtid 写入全局的 owned_gtids,并记录到线程的 owned_gtid 变量(注意:NDB 集群的处理有不同,这里我不一一介绍了)。
 
当事务结束时,MySQL 会调用 Gtid_state 的 update_on_commit / update_on_rollback 方法,把线程执行的 owned_gtid 从全局 owned_gtids 中删除。
 
全局 owned_gtids 常常用来反向查找执行事务的线程。有个需要关注的点,在 Gtid_state 的 acquire_ownership() 方法中,如果所给的 Gtid 在全局 owned_gtids 已经被标记成另一个线程执行,那么 MySQL 会尝试等待并检查这个线程是否被 kill。
 
Gtid_state 回顾
 
从上面 Gtid_state 的实现逻辑中,大家可以看到,在 MySQL 5.6 里一个全局事务 ID 的生命周期是这样的:
 
首先,执行数据库操作时,产生一个全局事务 ID,立即记录到全局和当前线程的 gtid_owned (owned_gtids)状态。
 
接着,提交数据库事务时,新产生的全局事务 ID 被写入 binlog,接着记录到 gtid_executed(logged_gtids)状态,然后从全局与线程区域的 gtid_owned (owned_gtids)状态中清除。
 
如果 DBA 执行了 purge 操作删除 binlog,被删除的全局事务 ID 会记录到 gtid_lost(lost_gtids)。但是,这些全局事务 ID 仍然包含在 gtid_executed(logged_gtids)全局状态里。
 
最后。
 
在上面的介绍中,我刻意没有提到 MySQL 是怎么保持这些全局事务状态的持久化的。因为这些和 5.6 新增的 binlog 事件 Gdit_log_event / Previous_gtid_log_event 有关。下一篇,我会先介绍一下 MySQL 5.6 对 binlog 格式的扩展,然后再介绍全局事务 ID 是如何作用于新的主备复制流程的。
 
(未完待续)
0
1
分享到:
评论
1 楼 mike79 2014-12-18  
有个问题,是关于gtid到底是在什么时候生成的。从refman和实验来看,应该是在事务提交时候才会分配gtid。比如事务A比事务B早开始,但是晚提交。在binlog中可以看到事务B的gtid小于事务A,说明是在提交时候才分配gtid。

“首先,执行数据库操作时,产生一个全局事务 ID,立即记录到全局和当前线程的 gtid_owned (owned_gtids)状态。
接着,提交数据库事务时,......”
但是从你的这段描述看,事务开始时候分配了gtid,而gtid_owned是用来记录那些已经分配了gtid,但是没有提交的事务。这个和实验结果有矛盾。

相关推荐

    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 5.6 & 5.7最优配置文件模板(my.ini)

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

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

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

    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