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基础第六篇:多对一关联关系的映射、分析...
--转自