深入理解MySQL 5.7 GTID系列(五) gtid_executed>id_purged什么时候更新
2018-01-28 00:00
281 查看
作者:高鹏(重庆八怪)原文地址:https://www.jianshu.com/p/905d7e89a305深入理解MySQL 5.7 GTID系列文章共十篇,本文为第四篇,第一篇:深入理解MySQL 5.7 GTID系列(一)
第二篇:深入理解MySQL 5.7 GTID系列(二):GTID相关内部数据结构第三篇:深入理解MySQL 5.7 GTID系列(三):GTID的生成时机第四篇:深入理解MySQL 5.7 GTID系列(四):mysql.gtid_executed&PREVIOUS GTID EVENT该系列文章将陆续不定期更新~本节将集中讨论下面三种GTID更新的时机,这部分相当重要,后面的故障案列会和这节有关。下面先来看一下他们的定义:mysql.gtid_executed表:GTID持久化的介质,MySQL启动阶段会读取这个表来获取[b]gtid_executed[/b]变量的值。
[b]gtid_executed[/b]变量(show global variables):MySQL数据库已经执行了哪些GTID事务,处于内存中。show slave status中的executed_gtid_set也取自这里。
gtid_purged变量(show global variables):由于BINLOG文件的删除(如purge binary logfiles或者超过expire_logs_days设置)已经丢失的GTID事务,同时在搭建备库的我们使用set global gtid_purged变量来提示MySQL哪些GTID事务我已经执行过了。
这也是我们DBA通常能够观察到的几种GTID,有了前文的描述我们知道其中mysql.gtid_executed表是一种GTID持久化的介质,而[b]gtid_executed[/b]变量和gtid_purged变量则对应了,gtid_state中的executed_gtids和lost_gtids内存数据。他们分别表示MySQL数据库执行了哪些GTID事务,有哪些GTID事务由于BINLOG文件的删除已经丢失了。
其次我们先来达成一个共识[b]gtid_executed[/b]变量一定是实时更新的不管主库和从库。我们的讨论分为主库,从库和通用从源码的角度进行详细讨论。并且约定都是打开GTID的情况下。最后给出最终总结。
在BINLOG发生切换(rotate)的时候保存直到上一个BINLOG文件执行过的全部GTID,它不是实时更新的。栈帧如下:
如前文所述ordered_commit flush阶段生成GTID,在COMMIT阶段才计入gtid_executed变量,它是实时更新的。栈帧如下:
在MySQL触发的清理BINLOG的情况下,比如purge binary logs to或者超过参数expire_logs_days设置的天数后自动删除,需要将丢失的GTID计入这个变量中。
栈帧如下:
MySQL删除BINLOG(如purge binary logfiles或者超过expire_logs_days设置)后需要确认gtid_purged变量(及gtid_state.lost_gtids)的值的时候。
随后我会单独一节来讲解MySQL GTID模块的初始化还会讲解这个函数。
前面已经说过这种情况下从库没有办法通过BINLOG来持久化sql_thread执行过的GTID事务,只能通过实时更新mysql.gtid_executed表来保存,所以必须要要实时将GTID持久化到mysql.gtid_executed表中。实际上实时保存mysql.gtid_executed发生在commit的preper阶段之前,也就是最开始。但是对于主库来讲由于还没有生成GTID,那么则不能写入栈帧如下:
这个和主库一样实时更新,不做讨论。[b]gtid_purged变量修改时机[/b]
由于压根没有binlog来记录已经执行过的Gtid事务,所以gtid_purged变量实时更新
其更改处于整个ha_commit_trans的结尾如下:
[b]mysql.gtid_executed表修改时机[/b]
和主库一致。及在进行日志切换的时候进行更新,不做讨论[b]gtid_executed变量修改时机[/b][b]和主库一样实时更新,不做讨论[/b]
[b]gtid_purged变量修改时机[/b]
和主库一致,BINLOG删除时更新,不做讨论
栈帧如下:
栈帧如下:
栈帧同上
在set global gitd_purged的时候,设置本变量
栈帧同上
在MySQL启动的时候初始化设置[b]GTID_EXECUTED变量,这个将在后面章节详细描述描述步骤。[/b]
3、gtid_purged变量修改时机在reset master的时候清空本变量
栈帧同上
在set global gitd_purged的时候,设置本变量
栈帧同上
在mysql启动的时候初始化设置[b]GTID_EXECUTED变量,这个将在后面章节详细描述描述步骤。[/b]
在BINLOG发生切换(rotate)的时候保存直到上一个BINLOG文件执行过的全部GTID,它不是实时更新的。
gtid_executed变量修改时机
如前文所述ordered_commit flush阶段生成GTID,在COMMIT阶段才计入gtid_executed变量,它是实时更新的。
gtid_purged变量修改时机
在MySQL触发的清理BINLOG的情况下,比如purge binary logs to或者超过参数expire_logs_days设置的天数后自动删除,需要将丢失的GTID计入这个变量中。
2、从库修改时机(1) [b]BINLOG关闭或者BINLOG开启参数log_slave_updates关闭的情况[/b]mysql.gtid_executed表修改时机
实时将GTID持久化到mysql.gtid_executed表中。
gtid_executed变量修改时机
它是实时更新的。
gtid_purged变量修改时机
由于压根没有BINLOG来记录已经执行过的GTID事务,所以gtid_purged变量实时更新
(2)[b]BINLOG开启同时参数log_slave_updates开启的情况[/b]mysql.gtid_executed表修改时机
进行日志切换的时候进行更新,同主库。
gtid_executed变量修改时机
实时更新,同主库。
gtid_purged变量修改时机
BINLOG删除时更新,同主库。
(1)在reset master的时候清空本表。
(2)在set global gitd_purged的时候,设置本表。
gtid_executed变量修改时机
(1)在reset master的时候清空本变量。
(2)在set global gitd_purged的时候,设置本变量。
(3)在MySQL启动的时候初始化设置gtid_executed变量。
gtid_purged变量修改时机
(1)在reset master的时候清空本变量。
(2)在set global gitd_purged的时候,设置本变量。
(3)在MySQL启动的时候初始化设置gtid_purged变量。
此外reset master命令除了完成上述功能还会清理BINLOG,重新初始化BINLOG从序号1开始。而set global gitd_purged参数一般只有在reset master后使用,用于搭建GTID从库或者处理GTID从库故障。学习完本节至少能学习到:1、主库和从库对于mysql.gtid_executed表,gtid_executed变量,gitd_purged变量
在各种情况下的修改时机
2、reset master做了什么关于GTID相关的工作
3、set global gitd_purged做了什么关于GTID相关的工作
对本文有任何疑问可扫码添加原文作者微信
知数堂叶金荣与吴炳锡联合打造领跑IT精英培训行业资深专家强强联合,倾心定制MySQL实战/MySQL优化 /大数据实战/ Python/ SQL优化数门精品课程紧随技术发展趋势,定期优化培训教案融入大量生产案例,贴合企业一线需求社群陪伴学习,一次报名,可学3期DBA、开发工程师必修课上千位学员已华丽转身,薪资翻番,职位提升改变已悄然发生,你还在等什么?
扫码下载知数堂精品课程试听视频(MySQL 实战/优化、大数据实战、Python开发,及SQL优化等课程)密码:hg3h
第二篇:深入理解MySQL 5.7 GTID系列(二):GTID相关内部数据结构第三篇:深入理解MySQL 5.7 GTID系列(三):GTID的生成时机第四篇:深入理解MySQL 5.7 GTID系列(四):mysql.gtid_executed&PREVIOUS GTID EVENT该系列文章将陆续不定期更新~本节将集中讨论下面三种GTID更新的时机,这部分相当重要,后面的故障案列会和这节有关。下面先来看一下他们的定义:mysql.gtid_executed表:GTID持久化的介质,MySQL启动阶段会读取这个表来获取[b]gtid_executed[/b]变量的值。
[b]gtid_executed[/b]变量(show global variables):MySQL数据库已经执行了哪些GTID事务,处于内存中。show slave status中的executed_gtid_set也取自这里。
gtid_purged变量(show global variables):由于BINLOG文件的删除(如purge binary logfiles或者超过expire_logs_days设置)已经丢失的GTID事务,同时在搭建备库的我们使用set global gtid_purged变量来提示MySQL哪些GTID事务我已经执行过了。
这也是我们DBA通常能够观察到的几种GTID,有了前文的描述我们知道其中mysql.gtid_executed表是一种GTID持久化的介质,而[b]gtid_executed[/b]变量和gtid_purged变量则对应了,gtid_state中的executed_gtids和lost_gtids内存数据。他们分别表示MySQL数据库执行了哪些GTID事务,有哪些GTID事务由于BINLOG文件的删除已经丢失了。
其次我们先来达成一个共识[b]gtid_executed[/b]变量一定是实时更新的不管主库和从库。我们的讨论分为主库,从库和通用从源码的角度进行详细讨论。并且约定都是打开GTID的情况下。最后给出最终总结。
一、主库修改时机
(1) BINLOG关闭
不生成gtid,mysql.gtid_executed表/gtid_executed变量/gtid_purged变量均不更新。(2)BINLOG打开
[b]mysql.gtid_executed表修改时机[/b]在BINLOG发生切换(rotate)的时候保存直到上一个BINLOG文件执行过的全部GTID,它不是实时更新的。栈帧如下:
#0 Gtid_table_persistor::save (this=0x2f9f9c0, gtid_set=0x7ffff03595a0) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_persist.cc:425 #1 0x0000000001803dbe in Gtid_state::save (this=0x2ff8bb0, gtid_set=0x7ffff03595a0) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:796 #2 0x0000000001803f62 in Gtid_state::save_gtids_of_last_binlog_into_table (this=0x2ff8bb0, on_rotation=true) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:835 #3 0x000000000185266d in MYSQL_BIN_LOG::new_file_impl (this=0x2dffc80, need_lock_log=false, extra_description_event=0x0) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:6751 #4 0x00000000018520a7 in MYSQL_BIN_LOG::new_file_without_locking (this=0x2dffc80, extra_description_event=0x0) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:6636 #5 0x0000000001853e67 in MYSQL_BIN_LOG::rotate (this=0x2dffc80, force_rotate=true, check_purge=0x7ffff0359c4b) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:7292其主要逻辑在gtid_state::save_gtids_of_last_binlog_into_table 中我们在随后的部分讨论这个函数逻辑。[b][b]gtid_executed[/b]变量修改时机[/b]
如前文所述ordered_commit flush阶段生成GTID,在COMMIT阶段才计入gtid_executed变量,它是实时更新的。栈帧如下:
#0 Gtid_set::_add_gtid (this=0x2ff8d38, sidno=1, gno=16) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid.h:1135 #1 0x0000000001804576 in Gtid_set::_add_gtid (this=0x2ff8d38, gtid=...) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid.h:1166 #2 0x00000000018024ba in Gtid_state::update_gtids_impl (this=0x2ff8bb0, thd=0x7fff2c000b70, is_commit=true) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:304 #3 0x00000000018020df in Gtid_state::update_on_commit (this=0x2ff8bb0, thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:148 #4 0x00000000018573d4 in MYSQL_BIN_LOG::process_commit_stage_queue (this=0x2dffc80, thd=0x7fff2c000b70, first=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:8646 #5 0x0000000001858b51 in MYSQL_BIN_LOG::ordered_commit (this=0x2dffc80, thd=0x7fff2c000b70, all=false, skip_commit=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:9304其主要逻辑在gtid_state::update_gtids_impl中我们在随后的部分讨论这个函数逻辑。[b]gtid_purged变量修改时机[/b]
在MySQL触发的清理BINLOG的情况下,比如purge binary logs to或者超过参数expire_logs_days设置的天数后自动删除,需要将丢失的GTID计入这个变量中。
栈帧如下:
#0 MYSQL_BIN_LOG::init_gtid_sets (this=0x2e00280, all_gtids=0x0, lost_gtids=0x2fcaee8, verify_checksum=false, need_lock=false, trx_parser=0x0, gtid_partial_trx=0x0, is_server_starting=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:4333 #1 0x0000000001850b8e in MYSQL_BIN_LOG::purge_logs (this=0x2e00280, to_log=0x7fff57a74ad0 "/root/mysql5.7.14/percona-server-5.7.14-7/mysql-test/var/mysqld.1/test.000202", included=false, need_lock_index=true, need_update_threads=true, decrease_log_space=0x0, auto_purge=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:6036 #2 0x0000000001848ecf in purge_master_logs (thd=0x7fff49200dc0, to_log=0x7fff492051a8 "test.000202") at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:2815其主要逻辑在MySQL_BIN_LOG::PURGE_LOGS中,我们随后查看其代码片段,同时MySQL_BIN_LOG::INIT_GTID_SETS函数是一个及其重要的函数,主要用在:MySQL启动时候初始化整个GTID_STATE中的各种GTID_SET。
MySQL删除BINLOG(如purge binary logfiles或者超过expire_logs_days设置)后需要确认gtid_purged变量(及gtid_state.lost_gtids)的值的时候。
随后我会单独一节来讲解MySQL GTID模块的初始化还会讲解这个函数。
二、主库修改时机源码函数分析
这里就对上面提到的主要逻辑函数进行分析gtid_state::save_gtids_of_last_binlog_into_table函数逻辑logged_gtids_last_binlog.add_interval_memory(PREALLOCATED_INTERVAL_COUNT, iv); //这里构建一个logged_gtids_last_binlog集合来保存切换后需要写入表和previous_gtids_logged的Gtid /* logged_gtids_last_binlog= executed_gtids - previous_gtids_logged - gtids_only_in_table */ global_sid_lock->wrlock();// ret= (logged_gtids_last_binlog.add_gtid_set(&executed_gtids) != //将当前执行过的Gtid全部加入logged_gtids_last_binlog 列如:executed_gtids start=1, end=27 RETURN_STATUS_OK); if (!ret) { logged_gtids_last_binlog.remove_gtid_set(&previous_gtids_logged); //获得上一个binlog文件包含的全部Gtid,并且做一个差集 列如:previous_gtids_logged 为start=1, end=25 //做完差集后logged_gtids_last_binlog为start=26, end=27 logged_gtids_last_binlog.remove_gtid_set(>ids_only_in_table);//此处主库一定为空,除非异常情况 if (!logged_gtids_last_binlog.is_empty()) { /* Prepare previous_gtids_logged for next binlog on binlog rotation */ if (on_rotation) ret= previous_gtids_logged.add_gtid_set(&logged_gtids_last_binlog);//将这个start=26, end=27的Gtid集合加入到previous_gtids_logged中,这样previous_gtids_logged也完整了 global_sid_lock->unlock(); /* Save set of GTIDs of the last binlog into gtid_executed table */ if (!ret) ret= save(&logged_gtids_last_binlog);//将这个start=26, end=27的Gtid集合写入到表mysql.gtid_executed表中 }gtid_state::update_gtids_impl函数代码片段
while (g.sidno != 0) { if (g.sidno != prev_sidno) sid_locks.lock(g.sidno); owned_gtids.remove_gtid(g); //从owned_gtid中去掉 git.next(); g= git.get(); if (is_commit) executed_gtids._add_gtid(g);//将这个Gtid加入到executed_gtids }mysql_binlog::purge_logs函数代码片段
if (!is_relay_log) { global_sid_lock->wrlock(); error= init_gtid_sets(NULL, const_cast<Gtid_set *>(gtid_state->get_lost_gtids()), opt_master_verify_checksum, false/*false=don't need lock*/, NULL/*trx_parser*/, NULL/*gtid_partial_trx*/);//这里我看到将gtid_state->lost_gtids直接传入给了init_gtid_sets //init_gtid_sets会做正向查找获得gtid_state->lost_gtids这个函数稍后 //详细讨论 global_sid_lock->unlock(); if (error) goto err; }
三、从库修改时机
(1) BINLOG关闭或者BINLOG开启参数log_slave_updates关闭的情况
将他们放到一起因为他们的表现完全一样。[b]mysql.gtid_executed表修改时机[/b]前面已经说过这种情况下从库没有办法通过BINLOG来持久化sql_thread执行过的GTID事务,只能通过实时更新mysql.gtid_executed表来保存,所以必须要要实时将GTID持久化到mysql.gtid_executed表中。实际上实时保存mysql.gtid_executed发生在commit的preper阶段之前,也就是最开始。但是对于主库来讲由于还没有生成GTID,那么则不能写入栈帧如下:
#0 commit_owned_gtids (thd=0x7fffec000970, all=false, need_clear_owned_gtid_ptr=0x7ffff08bf2cb) at /mysql/mysql-5.7.17/sql/handler.cc:1571 #1 0x0000000000f465c3 in ha_commit_trans (thd=0x7fffec000970, all=false, ignore_global_read_lock=false) at /mysql/mysql-5.7.17/sql/handler.cc:1669 #2 0x0000000001686f0d in trans_commit_stmt (thd=0x7fffec000970) at /mysql/mysql-5.7.17/sql/transaction.cc:458 #3 0x000000000180fb16 in rows_event_stmt_cleanup (rli=0x3937d30, thd=0x7fffec000970) at /mysql/mysql-5.7.17/sql/log_event.cc:11124 #4 0x000000000180f801 in Rows_log_event::do_apply_event (this=0x7fffec018020, rli=0x3937d30) at /mysql/mysql-5.7.17/sql/log_event.cc:11026 #5 0x00000000017f7b7b in Log_event::apply_event (this=0x7fffec018020, rli=0x3937d30) at /mysql/mysql-5.7.17/sql/log_event.cc:3324 #6 0x00000000018690a6 in apply_event_and_update_pos (ptr_ev=0x7ffff08bf830, thd=0x7fffec000970, rli=0x3937d30) at /mysql/mysql-5.7.17/sql/rpl_slave.cc:4702 #7 0x000000000186a75e in exec_relay_log_event (thd=0x7fffec000970, rli=0x3937d30) at /mysql/mysql-5.7.17/sql/rpl_slave.cc:5212 #8 0x0000000001870d07 in handle_slave_sql (arg=0x38cc1c0) at /mysql/mysql-5.7.17/sql/rpl_slave.cc:7320其主要逻辑包含在commit_owned_gtids中。[b]GTID_EXECUTED变量修改时机[/b]
这个和主库一样实时更新,不做讨论。[b]gtid_purged变量修改时机[/b]
由于压根没有binlog来记录已经执行过的Gtid事务,所以gtid_purged变量实时更新
其更改处于整个ha_commit_trans的结尾如下:
if (need_clear_owned_gtid) { thd->server_status&= ~SERVER_STATUS_IN_TRANS; /* Release the owned GTID when binlog is disabled, or binlog is enabled and log_slave_updates is disabled with slave SQL thread or slave worker thread. */ if (error) gtid_state->update_on_rollback(thd); else gtid_state->update_on_commit(thd); }栈帧如下(这个栈帧取值5.7.17):
#0 Gtid_set::_add_gtid (this=0x2f9ef40, sidno=2, gno=33083) at /mysql/mysql-5.7.17/sql/rpl_gtid.h:1136 #1 0x00000000017e9990 in Gtid_set::_add_gtid (this=0x2f9ef40, gtid=...) at /mysql/mysql-5.7.17/sql/rpl_gtid.h:1167 #2 0x00000000017e906e in Gtid_state::update_gtids_impl_own_gtid (this=0x2f9eca0, thd=0x7fffec000970, is_commit=true) at /mysql/mysql-5.7.17/sql/rpl_gtid_state.cc:939 #3 0x00000000017e6f3f in Gtid_state::update_gtids_impl (this=0x2f9eca0, thd=0x7fffec000970, is_commit=true) at /mysql/mysql-5.7.17/sql/rpl_gtid_state.cc:240 #4 0x00000000017e6d25 in Gtid_state::update_on_commit (this=0x2f9eca0, thd=0x7fffec000970) at /mysql/mysql-5.7.17/sql/rpl_gtid_state.cc:201 #5 0x0000000000f46d46 in ha_commit_trans (thd=0x7fffec000970, all=true, ignore_global_read_lock=false) at /mysql/mysql-5.7.17/sql/handler.cc:1846 #6 0x000000000168676b in trans_commit (thd=0x7fffec000970) at /mysql/mysql-5.7.17/sql/transaction.cc:239 #7 0x0000000001802aaa in Xid_log_event::do_commit (this=0x7fffec013c60, thd_arg=0x7fffec000970) at /mysql/mysql-5.7.17/sql/log_event.cc:6824 #8 0x00000000018034d7 in Xid_apply_log_event::do_apply_event (this=0x7fffec013ca8, rli=0x3937d30) at /mysql/mysql-5.7.17/sql/log_event.cc:7049当然其处理逻辑在gtid_state::update_gtids_impl_own_gtid中。
(2)BINLOG开启同时参数log_slave_updates开启的情况
这种情况sql_thread执行过的GTID事务可以通过BINLOG进行维护,所以mysql.gtid_executed表和gtid_purged变量不需要实时更新。[b]mysql.gtid_executed表修改时机[/b]
和主库一致。及在进行日志切换的时候进行更新,不做讨论[b]gtid_executed变量修改时机[/b][b]和主库一样实时更新,不做讨论[/b]
[b]gtid_purged变量修改时机[/b]
和主库一致,BINLOG删除时更新,不做讨论
四、从库修改时机源码函数分析
commit_owned_gtids函数逻辑://如果 binlog 没有开启包括(log_bin=0 和 sql_log_bin =0 )或者 开启了binlog 但是slave线程并且slave update 没有开启,都会记录gtid到表 //但是这里要注意一点在主库上如果binlog不开启那么thd->owned_gtid.sidno ==0 因为这个时候Gtid都没有生成,生成阶段为order_commit的commit阶段 if ((!opt_bin_log || (thd->slave_thread && !opt_log_slave_updates)) && (all || !thd->in_multi_stmt_transaction_mode()) && //all 代表是否是显示begin 事务in_multi_stmt_transaction_mode则相反 !thd->is_operating_gtid_table_implicitly && //是否是GTID_NEXT方式 flase !thd->is_operating_substatement_implicitly)//是否是子语句 flase { /* If the binary log is disabled for this thread (either by log_bin=0 or sql_log_bin=0 or by log_slave_updates=0 for a slave thread), then the statement will not be written to the binary log. In this case, we should save its GTID into mysql.gtid_executed table and @@GLOBAL.GTID_EXECUTED as it did when binlog is enabled. */ if (thd->owned_gtid.sidno > 0) { error= gtid_state->save(thd);//就是这里进行了mysql.gtid_executed表的实时更新 *need_clear_owned_gtid_ptr= true; } else if (thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS) *need_clear_owned_gtid_ptr= true; }gtid_state::update_gtids_impl_own_gtid 函数逻辑片段,这个函数是5.7.17的,5.7.14没有逻辑放到了gtid_state::update_gtids_impl中
if (is_commit) { DBUG_EXECUTE_IF( "rpl_gtid_update_on_commit_simulate_out_of_memory", DBUG_SET("+d,rpl_gtid_get_free_interval_simulate_out_of_memory");); /* Any session adds transaction owned GTID into global executed_gtids. If binlog is disabled, we report @@GLOBAL.GTID_PURGED from executed_gtids, since @@GLOBAL.GTID_PURGED and @@GLOBAL.GTID_EXECUTED are always same, so we did not save gtid into lost_gtids for every transaction for improving performance. If binlog is enabled and log_slave_updates is disabled, slave SQL thread or slave worker thread adds transaction owned GTID into global executed_gtids, lost_gtids and gtids_only_in_table. */ executed_gtids._add_gtid(thd->owned_gtid); //加入executed_gtids集合 thd->rpl_thd_ctx.session_gtids_ctx(). notify_after_gtid_executed_update(thd); if (thd->slave_thread && opt_bin_log && !opt_log_slave_updates)//如果是slave线程同时binlog开启了并且log_slave_updates关闭了 //如果binlog关闭则使用 executed_gtids这样提高性能前面的注释说了 { lost_gtids._add_gtid(thd->owned_gtid); //写入lost_gtids也就是更新参数gtid_purged变量 gtids_only_in_table._add_gtid(thd->owned_gtid); } }
五、通用更改时机
[b]1、mysql.gtid_executed表修改时机[/b]在reset master的时候清空本表栈帧如下:
#0 Gtid_table_persistor::delete_all (this=0x2f9f9c0, table=0x7fff2c0116a0) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_persist.cc:795 #1 0x000000000180a4ef in Gtid_table_persistor::reset (this=0x2f9f9c0, thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_persist.cc:689 #2 0x0000000001801f2e in Gtid_state::clear (this=0x2ff8bb0, thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:36 #3 0x000000000184fee6 in MYSQL_BIN_LOG::reset_logs (this=0x2dffe80, thd=0x7fff2c000b70, delete_only=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:5586 #4 0x0000000001872308 in reset_master (thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_master.cc:587其主要逻辑在gtid_state::clear中。在set global gitd_purged的时候,设置本表
栈帧如下:
#0 Gtid_table_persistor::save (this=0x2f9f9c0, gtid_set=0x7ffff0359a70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_persist.cc:425 #1 0x000000000180400a in Gtid_state::save (this=0x2ff8bb0, gtid_set=0x7ffff0359a70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:796 #2 0x0000000001803c25 in Gtid_state::add_lost_gtids (this=0x2ff8bb0, gtid_set=0x7ffff0359a70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:737 #3 0x00000000016778f3 in Sys_var_gtid_purged::global_update (this=0x2de9fe0, thd=0x7fff2c000b70, var=0x7fff2c006630) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sys_vars.cc:5888 #4 0x00000000014d5cd1 in sys_var::update (this=0x2de9fe0, thd=0x7fff2c000b70, var=0x7fff2c006630) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/set_var.cc:184 #5 0x00000000014d74ee in set_var::update (this=0x7fff2c006630, thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/set_var.cc:812 #6 0x00000000014d6d1a in sql_set_variables (thd=0x7fff2c000b70, var_list=0x7fff2c003528) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/set_var.cc:669其主要逻辑在gtid_state::add_lost_gtids中。[b]2、gtid_executed变量修改时机[/b]在reset master的时候清空本变量
栈帧同上
在set global gitd_purged的时候,设置本变量
栈帧同上
在MySQL启动的时候初始化设置[b]GTID_EXECUTED变量,这个将在后面章节详细描述描述步骤。[/b]
3、gtid_purged变量修改时机在reset master的时候清空本变量
栈帧同上
在set global gitd_purged的时候,设置本变量
栈帧同上
在mysql启动的时候初始化设置[b]GTID_EXECUTED变量,这个将在后面章节详细描述描述步骤。[/b]
六、通用更改时机源码函数分析
gtid_state::clear函数逻辑int Gtid_state::clear(THD *thd) { .... // the wrlock implies that no other thread can hold any of the mutexes sid_lock->assert_some_wrlock(); lost_gtids.clear();//此处清空gtid_purged变量 executed_gtids.clear();//此处清空gtid_executed变量 gtids_only_in_table.clear();//清空only in table Gtid set previous_gtids_logged.clear();//清空 previous gtids logged Gtid set /* Reset gtid_executed table. */ if ((ret= gtid_table_persistor->reset(thd)) == 1)//此处清空mysql.gtid_executed表 { /* Gtid table is not ready to be used, so failed to open it. Ignore the error. */ thd->clear_error(); ret= 0; } next_free_gno= 1; DBUG_RETURN(ret); }gtid_state::add_lost_gtids函数逻辑
enum_return_status Gtid_state::add_lost_gtids(const Gtid_set *gtid_set) { ...... if (save(gtid_set)) //此处将set gtid_purge的值加入到mysql.gtid_executed表中 RETURN_REPORTED_ERROR; PROPAGATE_REPORTED_ERROR(gtids_only_in_table.add_gtid_set(gtid_set)); PROPAGATE_REPORTED_ERROR(lost_gtids.add_gtid_set(gtid_set));//此处将set gtid_purge的值加入到gtid_purge变量中 PROPAGATE_REPORTED_ERROR(executed_gtids.add_gtid_set(gtid_set));//此处将set gtid_purge的值加入到gtid_executed变量中 lock_sidnos(gtid_set); broadcast_sidnos(gtid_set); unlock_sidnos(gtid_set); DBUG_RETURN(RETURN_STATUS_OK); }
七、本节小结
为了方便这里将上面的重点文字描述进行提取,去掉源码部分,方便大家阅读1、主库修改时机
(1)[b]BINLOG关闭[/b]不生成gtid,mysql.gtid_executed表/gtid_executed变量/gtid_purged变量均不更新。(2)[b]BINLOG打开[/b]mysql.gtid_executed表修改时机在BINLOG发生切换(rotate)的时候保存直到上一个BINLOG文件执行过的全部GTID,它不是实时更新的。
gtid_executed变量修改时机
如前文所述ordered_commit flush阶段生成GTID,在COMMIT阶段才计入gtid_executed变量,它是实时更新的。
gtid_purged变量修改时机
在MySQL触发的清理BINLOG的情况下,比如purge binary logs to或者超过参数expire_logs_days设置的天数后自动删除,需要将丢失的GTID计入这个变量中。
2、从库修改时机(1) [b]BINLOG关闭或者BINLOG开启参数log_slave_updates关闭的情况[/b]mysql.gtid_executed表修改时机
实时将GTID持久化到mysql.gtid_executed表中。
gtid_executed变量修改时机
它是实时更新的。
gtid_purged变量修改时机
由于压根没有BINLOG来记录已经执行过的GTID事务,所以gtid_purged变量实时更新
(2)[b]BINLOG开启同时参数log_slave_updates开启的情况[/b]mysql.gtid_executed表修改时机
进行日志切换的时候进行更新,同主库。
gtid_executed变量修改时机
实时更新,同主库。
gtid_purged变量修改时机
BINLOG删除时更新,同主库。
3、通用修改时机
mysql.gtid_executed表修改时机(1)在reset master的时候清空本表。
(2)在set global gitd_purged的时候,设置本表。
gtid_executed变量修改时机
(1)在reset master的时候清空本变量。
(2)在set global gitd_purged的时候,设置本变量。
(3)在MySQL启动的时候初始化设置gtid_executed变量。
gtid_purged变量修改时机
(1)在reset master的时候清空本变量。
(2)在set global gitd_purged的时候,设置本变量。
(3)在MySQL启动的时候初始化设置gtid_purged变量。
此外reset master命令除了完成上述功能还会清理BINLOG,重新初始化BINLOG从序号1开始。而set global gitd_purged参数一般只有在reset master后使用,用于搭建GTID从库或者处理GTID从库故障。学习完本节至少能学习到:1、主库和从库对于mysql.gtid_executed表,gtid_executed变量,gitd_purged变量
在各种情况下的修改时机
2、reset master做了什么关于GTID相关的工作
3、set global gitd_purged做了什么关于GTID相关的工作
对本文有任何疑问可扫码添加原文作者微信
知数堂叶金荣与吴炳锡联合打造领跑IT精英培训行业资深专家强强联合,倾心定制MySQL实战/MySQL优化 /大数据实战/ Python/ SQL优化数门精品课程紧随技术发展趋势,定期优化培训教案融入大量生产案例,贴合企业一线需求社群陪伴学习,一次报名,可学3期DBA、开发工程师必修课上千位学员已华丽转身,薪资翻番,职位提升改变已悄然发生,你还在等什么?
扫码下载知数堂精品课程试听视频(MySQL 实战/优化、大数据实战、Python开发,及SQL优化等课程)密码:hg3h
相关文章推荐
- 深入理解MySQL 5.7 GTID系列(四):mysql.gtid_executed&PREVIOUS GTID EVENT
- 深入理解MySQL 5.7 GTID系列(四):mysql.gtid_executed&PREVIOUS GTID EVENT
- 深入理解MySQL 5.7 GTID系列(二):GTID相关内部数据结构
- 深入理解MySQL 5.7 GTID系列(六):MySQL启动初始化GTID模块
- 深入理解MySQL 5.7 GTID系列(三):GTID的生成时机
- 深入理解MySQL 5.7 GTID系列(一)
- 深入理解MySQL 5.7 GTID系列(八):GTID带来的运维改变
- 深入理解MySQL 5.7 GTID系列(一)
- 深入理解MySQL 5.7 GTID系列(七)binlog_gtid_simple_recovery参数的影响总结
- 深入理解mysql之BDB系列(1)---BDB相关基础知识
- MySQL复制之gtid_purged与gtid_executed
- 深入理解mysql之BDB系列(2)---数据元页结构
- 深入理解mysql之BDB系列(1)---BDB相关基础知识(摘自老杨)
- 深入理解mysql之BDB系列(3)---数据页结构
- Android 源码系列之<六>从源码的角度深入理解LayoutInflater.Factory之主题切换(下)
- Android 源码系列之<四>从源码的角度深入理解LayoutInflater.Factory之主题切换(上)
- [深入理解MySQL系列] - sort_buffer
- mysql.gtid_executed表的更新机制
- 深入理解mysql之BDB系列(2)---数据元页结构(摘自老杨)
- MySQL 5.7中新增的表gtid_executed,看看是否解决了你的痛点