全局事务状态 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)状态。
如果 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 是如何作用于新的主备复制流程的。
- [转]MySQL 5.6 全局事务 ID(GTID)实现原理(三)
原文连接:http://qing.blog.sina.com.cn/1757661907/68c3cad333002s5l.html 原文作者:淘长源 转载注明以上信息 这是 MySQL 5.6 全局 ...
- [转]MySQL 5.6 全局事务 ID(GTID)实现原理(一)
原文作者:淘长源 原文连接:http://qing.blog.sina.com.cn/1757661907/68c3cad333002qhe.html 转载注明以上信息 MySQL 5.6 的新特 ...
- [mysql] MariaDB 10.0.10 GTID复制
一:概念理解: 1.TID:Transaction ID,即Mysql服务器的事务ID号. 2.GTID:Global Transaction ID,全局事务ID,在整个主从复制架构中任何两个事 ...
- MysqL主从复制_模式之GTID复制
基于GTID的复制是从Mysql5.6开始支持的一种新的复制方式,此方式与传统基于日志的方式存在很大的差异,在原来的基于日志的复制中,从服务器连接到主服务器并告诉主服务器要从哪个二进制日志的偏移量开始 ...
- 与MySQL传统复制相比,GTID有哪些独特的复制姿势?
与MySQL传统复制相比,GTID有哪些独特的复制姿势? http://mp.weixin.qq.com/s/IF1Pld-wGW0q2NiBjMXwfg 陈华军,苏宁云商IT总部资深技术经理,从事数 ...
- 配置percona mysql server 5.7基于gtid主主复制架构
配置mysql基于gtid主主复制架构 环境: 操作系统 centos7. x86_64 mysql版本:Percona-Server-- 测试环境: node1 10.11.0.210 node2 ...
- MySQL 5.6.10 跨平台GTID复制实践
根据业务需要,建立MySQL复制来实现数据冗余. 1:binlog_format 默认值是:statement 有效值: ROW,基于行的复制 STATEMENT 基于语句级别的复制 MASTER ...
- MYSQL获取自增ID的四种方法
MYSQL获取自增ID的四种方法 1. select max(id) from tablename 2.SELECT LAST_INSERT_ID() 函数 LAST_INSERT_ID 是与tabl ...
- mysql 数据库自增id 的总结
有一个表StuInfo,里面只有两列 StuID,StuName其中StuID是int型,主键,自增列.现在我要插入数据,让他自动的向上增长,insert into StuInfo(StuID,Stu ...
- RAC之RMAN恢复
之前整理的RMAN 有关还原的文章: RMAN 系列(五) ---- RMAN 还原 与 恢复 http://blog.csdn.net/tianlesoftware/archive/2010/07/ ...
- Effective Java实作toString() - 就是爱Java
Object class中,也定义了toString()这个方法,因此所有的class也都继承这个方法.默认是传回这个对象完整类别名称,后面接一个"@",及一个不带正副号的十六进制 ...
- (转)C#在父窗口中调用子窗口的过程(无法访问已释放的对象)
C#在父窗口中调用子窗口的过程: 1. 创建子窗口对象 2. 显示子窗口对象 笔者的程序中,主窗体MainFrm通过菜单调用子窗口ChildFrm.在窗体中定义了子窗口对象,然后在菜单项点击事件中 ...
- oracle starup报错
今天在linux里面安装Oracle的时候出现一个报错,忽略报错安装之后,数据库启动的时候报错: 从网上找到的解决方法: 创建实例后,进入sqlplus启动报错: sqlplus / as sysdb ...
- sqlplus 一次奇葩问题 HTTP proxy setting has incorrect value
y@y:~$ sqlplus Error 46 initializing SQL*PlusHTTP proxy setting has incorrect valueSP2-1502: The HTT ...
- kibana 统计每天注册数
- Linux中使用mysqldump对MySQL数据库进行定时备份
#!/bin/bash PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH expo ...
- 再造轮子之网易彩票-第二季(IOS 篇 by sixleaves)
02-彩票项目第二季 2.封装SWPTabBar方式一 接着我们思考如何进行封装.前面已经将过了为什么要封装, 和封装达到的效果.这里我们主要有两种封装方式,分别是站在不同的角度上看待问题.虽然角度不 ...
- HOJ 1096 Divided Product (DFS)
时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Given two positive integers N and M, please divide N into sev ...
- (转)linux下fork的运行机制
转载http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html 给出如下C程序,在linux下使用g ...