MySQL 5.7.5: GTID_EXECUTED系统表_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 2022 | 回复: 0   主题: MySQL 5.7.5: GTID_EXECUTED系统表        下一篇 
ab19890824
注册用户
等级:少尉
经验:351
发帖:92
精华:0
注册:2011-11-21
状态:离线
发送短消息息给ab19890824 加好友    发送短消息息给ab19890824 发消息
发表于: IP:您无权察看 2014-12-22 16:08:47 | [全部帖] [楼主帖] 楼主

Gtid是从5.6开始推出的杀手级特性,通过GTID特性,极大的提升了主备切换的效率和一致性,

在MySQL5.7.5里引入了一个新的系统表GTID_EXECUTED:

root@mysql 11:29:40>SHOW CREATE TABLE mysql.gtid_executed\G
*************************** 1. row ***************************
Table: gtid_executed
Create Table: CREATE TABLE `gtid_executed` (
`source_uuid` char(36) NOT NULL COMMENT ‘uuid of the source where the transaction was originally executed.’,
`interval_start` bigint(20) NOT NULL COMMENT ‘First number of interval.’,
`interval_end` bigint(20) NOT NULL COMMENT ‘Last number of interval.’,
PRIMARY KEY (`source_uuid`,`interval_start`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)


表的描述参考官方文档:

http://dev.mysql.com/doc/refman/5.7/en/replication-gtids-concepts.html#replication-gtids-gtid-executed-table


对应worklog: http://dev.mysql.com/worklog/task/?id=6559

该特性最大的用处就是,如果我们的备库只是作为只读节点,那么就可以关闭复制线程的binlog来降低复制的开销(关闭log_slave_updates),同时还会维持SQL线程拥有的事务GTID到系统表中。这样即使主备切换,我们也不会丢失GTID。而在之前的版本中,是不允许在打开GTID时关闭log_slave_updates的。

当然了,如果你的备库是级联的一部分,也就是说,是另外一台备库的主库,这个特性就发挥不了作用啦。

下面简单过一下相关的代码实现逻辑

0.background
新增源代码文件sql/rpl_gtid_ persist.cc 及 sql/rpl_gtid_persist.h, 用于处理新增的GTID持久化逻辑。

新增类Gtid_table_persistor 及类对象gtid_table_persistor, 用于操作新增的系统表

北京联动北方科技有限公司

Gtid_state增加新成员:

previous_gtids_logged


之前一个 Binlog 包含的 gtid 集合,不包含 gtids_only_in_table , ref :MYSQL_BIN_LOG::open_binlog
1.记录GTID_EXECUTED表
根据文档描述,分三种情况使用该表:

一种是禁止binlog时(不是简单的设置sql_log_bin),该表记录每个事务拥有的GTID,并定期进行表压缩。

第二种是打开binlog,并且log_slave_updates打开,在binlog文件rotate或者shutdown实例时,记录GTID集合

第三种是打开Binlog,但log_slave_updates关闭,除了在rotate或shutdown时记录之前的GTID SET 还会记录SQL线程执行的事务的GTID SET.

在事务提交,进入函数ha_commit_trans时:

满足如下条件,事务拥有的gtid被记录入gtid_executed表中

1547 /*
1548 Save transaction owned gtid into table before transaction prepare
1549 if binlog is disabled, or binlog is enabled and log_slave_updates
1550 is disabled with slave SQL thread or slave worker thread.
1551 */
1552 if ((!opt_bin_log || (thd->slave_thread && !opt_log_slave_updates)) &&
1553 (all || !thd->in_multi_stmt_transaction_mode()) &&
1554 !thd->owned_gtid.is_null() && !thd->is_operating_gtid_table)
1555 {
      1556 error= gtid_state->save(thd);
      1557 need_clear_owned_gtid= true;
1558 }


在完成innodb commit后,调用Gtid_state::update_on_commit,从函数逻辑可以看到:

#如果binlog关闭,所有拥有GTID的事务都会加到executed_gtids集合中;
#如果binlog打开,并且log_slave_updates是关闭时,复制sql线程会将其拥有的GTID加到executed_gtids集合和gtids_only_in_table中。


当我们手动执行FLUSH LOGS,触发一次binlog rotate,也会写入到gtid_executed表中,堆栈如下:

MYSQL_BIN_LOG::new_file_impl
Gtid_state::save_gtids_of_last_binlog_into_table
Gtid_table_persistor::save


2.压缩GTID表
如果备库复制线程的log_slave_updates关闭,那么会大量插入GTID到系统表中(为什么用插入,而不用update呢 ? 原因是为了避免多线程复制时更新表热点记录)。因此需要定期将插入其中的GTID合并成一个集合。这是由一个独立线程来完成的。

新引入参数executed_gtids_compression_period,   用于控制线程多久被唤醒来压缩表gtid_executed,默认值为1000,表示每执行1000个事务后进行一次压缩。

在函数Gtid_table_persistor::save(THD *thd, Gtid *gtid)中进行判断,是否需要唤醒压缩线程

创建线程函数create_compress_gtid_table_thread

中断线程函数terminate_compress_gtid_table_thread

线程入口函数:compress_gtid_table

线程唤醒后,会调用Gtid_table_persistor::compress —>compress_in_single_transaction进行GTID合并。

3.设置GTID_PURGED
mysql实例启动时初始化,会同时读取binlog文件和gtid_executed表来初始化集合

quoted code   ( mysqld.cc )


第一种情况:binlog打开时

4484       if (mysql_bin_log.init_gtid_sets(&logged_gtids_binlog,
4485                                         &purged_gtids_binlog,
4486                                         NULL,
4487                                         opt_master_verify_checksum,
4488                                         true/*true=need lock*/,
4489                                         true) ||
4490           gtid_state->fetch_gtids(executed_gtids) == -1)
4491         unireg_abort(1);


完成初始化logged_gtids_binlog, purged_gtids_binlog 以及从gtid_executed表中读取GTID到executed_gtids后。

logged_gtids_binlog收集自binlog,表示当前记录在binlog中的gtid集合。如果logged_gtids_binlog不为空,且不是executed_gtids的子集,那么未保存到表中的gtid集合为:

unsaved_gtids_in_table.add_gtid_set(&logged_gtids_binlog);
unsaved_gtids_in_table.remove_gtid_set(executed_gtids);


然后将这一部分保存到gtid_executed表中。

第二种情况:binlog关闭

4585 else if (gtid_mode > GTID_MODE_OFF)
4586 {
      4587 /*
      4588 If gtid_mode is enabled and binlog is disabled, initialize
      4589 executed_gtids from gtid_executed table.
      4590 */
      4591 if (gtid_state->fetch_gtids(executed_gtids) == -1)
      4592 unireg_abort(1);
4593 }
4594 }


在初始化GTID_PURGED时,当binglog打开,从lost_gtids获取,否则从executed_gtids获取

参考:Sys_var_gtid_purged::global_value_ptr

4. 重置

RESET MASTER会重置该表

backtrace :
reset_master
MYSQL_BIN_LOG::reset_logs
Gtid_state::clear
Gtid_table_persistor::reset


5. 相关代码:

http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8142


3. oracle 索引优化
4. SQL Server 内存中OLTP内部机制概述(三)
5. [Nhibernate]SchemaExport工具的使用(一)——通过映射文件修改数...
6. 【SSH三大框架】Hibernate基础第六篇:多对一关联关系的映射、分析...

--转自 北京联动北方科技有限公司




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论