app开发者平台在数字化时代的重要性与发展趋势解析
754
2022-09-01
gtid
gtid知识:
一、gtid持久化介质
01 、mysql.gtid_executed表:
work@master (mysql) > show create table gtid_executed\G;*************************** 1. row *************************** Table: gtid_executedCreate 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=utf8mb4 STATS_PERSISTENT=01 row in set (0.07 sec)ERROR: No query specifiedMon May 11 16:56:12 2020
02、binlog中的gtid_event
# at 120#151222 9:07:58 server id 1026872634 end_log_pos 247 CRC32 0xedf993a8 Previous-GTIDs# b3485508-883f-11e5-85fb-e41f136aba3e:1-14,# b694c8b2-883f-11e5-85fb-e41f136aba3e:1-10115960:12000000-12000005# at 247#151222 9:08:03 server id 1026872625 end_log_pos 295 CRC32 0xc3d3d8ee GTID [ commit =yes]SET @@SESSION.GTID_NEXT= 'b694c8b2-883f-11e5-85fb-e41f136aba3e:10115961' /*!*/;# at 295#151222 9:08:03 server id 1026872625 end_log_pos 370 CRC32 0x0a32d229 Query thread_id=18 exec_time=1 error_code=0BEGIN/*!*/;# at 370#151222 9:08:03 server id 1026872625 end_log_pos 480 CRC32 0x3c0e094f Query thread_id=18 exec_time=1 error_code=0use `db`/*!*/;SET TIMESTAMP =1450746483/*!*/;update tb set val = val + 1 where id = 1/*!*/;# at 480#151222 9:08:03 server id 1026872625 end_log_pos 511 CRC32 0x5772f16b Xid = 6813913COMMIT /*!*/;# at 511#151222 9:10:19 server id 1026872625 end_log_pos 559 CRC32 0x3ac30191 GTID [ commit =yes]SET @@SESSION.GTID_NEXT= 'b694c8b2-883f-11e5-85fb-e41f136aba3e:10115962' /*!*/;# at 559#151222 9:10:19 server id 1026872625 end_log_pos 634 CRC32 0x83a74912 Query thread_id=18 exec_time=0 error_code=0SET TIMESTAMP =1450746619/*!*/;BEGIN/*!*/;# at 634#151222 9:10:19 server id 1026872625 end_log_pos 744 CRC32 0x581f6031 Query thread_id=18 exec_time=0 error_code=0SET TIMESTAMP =1450746619/*!*/;update tb set val = val + 1 where id = 1/*!*/;# at 744#151222 9:10:19 server id 1026872625 end_log_pos 775 CRC32 0x793f8e34 Xid = 6813916COMMIT /*!*/;
二、gtid相关变量和表
01、mysql.gtid_executed表
表中。只有从库在binlog或log_slave_updates至少一个关闭时,才会实时更新的。
1. 执行 reset master 时,则删除该表所有记录。2. 执行 set global gitd_purged='' 时,则插入对应的记录到mysql.gtid_executed表,且同时更新gtid_executed为和gtid_purged相同的值,即始终保持gtid_purged是gtid_executed的子集。3. 主库:若binlog关闭,则不更新;若binlog打开,则binlog发生rotate切换时,会更新该表数据。4. 从库:若binlog或log_slave_updates至少一个关闭,则实时更新;若binlog和log_slave_updates都开启,则binlog发生rotate切换时,会更新该表数据。
02、gtid_executed变量
含义:数据库已经执行了哪些Gtid事物,存储在内存中。
show slave status中的Executed_Gtid_Set也取自这里。
gtid_executed为空有两种情况:一是执行reset master;二是之前没有启动过基于GTID的复制。
1. 执行 reset master 时,则该变量设置为空。2. 执行 set global gitd_purged='' 时,则插入对应的记录到mysql.gtid_executed表,且同时更新gtid_executed为和gtid_purged相同的值,即始终保持gtid_purged是gtid_executed的子集。3. mysql启动时,通过读取mysql.gtid_executed表的数据来初始化gtid_executed变量。4. 只有当主库在关闭binlog的时候,不会更新gtid_executed变量;其余情况,都会实时更新gtid_executed变量。
03、gitd_purged变量
含义:全局变量。用于记录已经被清除了的binlog事务集合,gitd_purged变量是gtid_executed变量的子集。
只有gtid_executed为空时,才能手动设置gitd_purged变量。
1. 执行 reset master 时,则该变量设置为空。2. 执行 set global gitd_purged='XXX' 时,则插入对应的记录到mysql.gtid_executed表,且同时更新gtid_executed为和gtid_purged相同的值,即始终保持gtid_purged是gtid_executed的子集。 用来来提示Mysql,哪些Gtid事务我已经执行过了。用于搭建从库时,使用极多。通常是先在从库执行:reset master;然后再在从库执行:set global gitd_purged='XXX', 注意,这里的XXX需要结合该从库Retrieved_Gtid_Set和Executed_Gtid_Set的并集,还要加上主库的Executed_Gtid_Set中存在的,但不是该主库产生的gtid,且该从库没有的gtid。 但是这样有个隐患,就是主库上有其他机器执行过的gtid而得到的数据,但是该从库却没有真正存在这些数据,而你在该从库上却设置为这些gtid事务是自己purge掉了,其实自己压根没有这些数据,这样就导致从库的数据少于主库,即丢掉了数据。3. mysql启动时,通过读取mysql.gtid_executed表的数据来初始化gtid_executed变量。4. 主库:若binlog关闭,则不更新gitd_purged变量;若binlog打开,则binlog被清理时,会更新gitd_purged变量。5. 从库:若binlog或log_slave_updates至少一个关闭,则实时更新gitd_purged变量;若binlog和log_slave_updates都开启,则binlog被清理时,会更新gitd_purged变量。########################################################################################################################################################################################手动删除binlog: show binary logs; purge binary logs to 'mysql-bin.000046'; purge binary logs before '2020-10-10 10:10:10';自动删除binlog: expire_logs_days时间到了,执行binlog删除
跳过gtid事务:
(1)停止复制: stop slave;(2)重置master: reset master;(3)设置gtid_purged变量: set global gtid_purged='XXX';(4)开启复制:
3,使用空事务处理故障情况1:主键重复# Last_Error: Could not execute Write_rows event on table test.a; Duplicate entry '500' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql.000005, end_log_pos 651107# 方法1:# 注入空事务 Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: 7abe211e-fb4f-11e7-b16e-000c29ba88ca:66253-68381:69091-70362 Executed_Gtid_Set: 7abe211e-fb4f-11e7-b16e-000c29ba88ca:1-70362,9a455b69-fb4f-11e7-b993-000c29e8a43c:1####################################################(root@Slave)[tempdb]>stop slave sql_thread;(root@Slave)[tempdb]>set gtid_next='7abe211e-fb4f-11e7-b16e-000c29ba88ca:70363';(root@Slave)[tempdb]>begin;commit;(root@Slave)[tempdb]>set gtid_next='AUTOMATIC';(root@Slave)[tempdb]>start slave sql_thread;(root@Slave)[tempdb]>show slave status \G
04、Executed_Gtid_Set
含义:
1. 在主库中,执行 show master status命令,所得Executed_Gtid_Set,就是和全局变量gitd_executed相同值,任何时候,两者完全相同值。2. 在从库中,执行 show slave status命令,所得Executed_Gtid_Set,就是和全局变量gitd_executed相同值,任何时候,两者完全相同值。
05、Retrieved_Gtid_Set
含义:仅在从库中才有,在主库中不存在。
06、Previous-GTIDs
1. Previous_gtid_log_event在每个binlog 头部都会有每次binlog rotate的时候存储在binlog头部,Previous-GTIDs在binlog中只会存储在这台机器上执行过的所有binlog,不包括手动设置gtid_purged值。 换句话说,如果你手动set global gtid_purged=xx; 那么xx是不会记录在Previous_gtid_log_event中的。
07、gtid_next变量
跳过gtid事务:
1) 停止slave进程: mysql> stop slave; (2) 设置事务号,事务号从Retrieved_Gtid_Set获取: 在session里设置gtid_next,即跳过这个GTID mysql> SET @@sission.gtid_next= '8f9e146f-0a18-11e7-810a-0050568833c8:4' (3)设置空事物 mysql> begin; commit;(4)恢复事物号 mysql> set session gtid_next= automatic;(5) 启动slave进程 mysql>
08、gtid_owned
08、gtid_mode
09、enforce_gtid_consistency
10、gtid_executed_compression_period
1、gtid配置
关闭GTID模式。但是gtid_mode是只读的,可添加到配置文件中,然后重启mysqld来开启GTID模式。相关配置项如下:gtid-mode = ONenforce_gtid_consistency = 1log-slave-updates = 1log-bin = mysql-binlog-bin-index = mysql-bin.index
2、查看配置
> show global variables like 'gtid_%'\G;*************************** 1. row ***************************Variable_name: gtid_executed Value: 5a1a41db-9f15-11e9-a991-e4434b210720:1-2,5aa95098-9f15-11e9-98f3-e4434b5a47f8:1-429,5bcba8f5-9f15-11e9-9b14-e4434b210748:1-6319147104,5d2b585f-9f15-11e9-a58d-e4434b2106e8:1-1373519,62cdce4f-9f15-11e9-9f0d-e4434b21b430:1-2,66b80dbd-c979-11e9-8582-246e96c58570:1,85e1f282-f3a7-11e9-a222-e4434b2106e8:1-24*************************** 2. row ***************************Variable_name: gtid_executed_compression_period Value: 1000*************************** 3. row ***************************Variable_name: gtid_mode Value: ON*************************** 4. row ***************************Variable_name: gtid_owned Value:*************************** 5. row ***************************Variable_name: gtid_purged Value: 5a1a41db-9f15-11e9-a991-e4434b210720:1-2,5aa95098-9f15-11e9-98f3-e4434b5a47f8:1-429,5bcba8f5-9f15-11e9-9b14-e4434b210748:1-6047460531:6047460533,5d2b585f-9f15-11e9-a58d-e4434b2106e8:1-1373519,62cdce4f-9f15-11e9-9f0d-e4434b21b430:1-2,66b80dbd-c979-11e9-8582-246e96c58570:1,85e1f282-f3a7-11e9-a222-e4434b2106e8:1-225 rows in set (0.00 sec)ERROR:No query specifiedSun Dec 8 16:57:49 2019
这里有4个变量,其中gtid_mode已经介绍过了,其他3个变量的含义如下
gtid_executed:这既是一个Global级别的变量,又是一个Session级别的变量,是只读变量。Global级别的gtid_executed表示当前实例已经执行过的GTID集合。Session级别的gtid_executed一般情况下是空的。
gtid_owned:这既是一个Global级别的变量,又是一个Session级别的变量,是只读变量。Global级别的gtid_owned表示当前实例正在执行中的GTID,以及对应的线程id。Session级别的gtid_owned一般情况下是空的。
gtid_purged:这是一个Global级别的变量,可动态修改。我们知道binlog可以被purge掉,gtid_purged表示当前实例中已经被purge掉的GTID集合,很明显gtid_purged是gtid_executed的子集。但是gtid_purged也不是可以随意修改的,必须在@@global.gtid_executed是空的情况下,才可以动态设置gtid_purged。
binlog文件中的gtid
# at 120#151222 9:07:58 server id 1026872634 end_log_pos 247 CRC32 0xedf993a8 Previous-GTIDs# b3485508-883f-11e5-85fb-e41f136aba3e:1-14,# b694c8b2-883f-11e5-85fb-e41f136aba3e:1-10115960:12000000-12000005# at 247#151222 9:08:03 server id 1026872625 end_log_pos 295 CRC32 0xc3d3d8ee GTID [ commit =yes]SET @@SESSION.GTID_NEXT= 'b694c8b2-883f-11e5-85fb-e41f136aba3e:10115961' /*!*/;# at 295#151222 9:08:03 server id 1026872625 end_log_pos 370 CRC32 0x0a32d229 Query thread_id=18 exec_time=1 error_code=0BEGIN/*!*/;# at 370#151222 9:08:03 server id 1026872625 end_log_pos 480 CRC32 0x3c0e094f Query thread_id=18 exec_time=1 error_code=0use `db`/*!*/;SET TIMESTAMP =1450746483/*!*/;update tb set val = val + 1 where id = 1/*!*/;# at 480#151222 9:08:03 server id 1026872625 end_log_pos 511 CRC32 0x5772f16b Xid = 6813913COMMIT /*!*/;# at 511#151222 9:10:19 server id 1026872625 end_log_pos 559 CRC32 0x3ac30191 GTID [ commit =yes]SET @@SESSION.GTID_NEXT= 'b694c8b2-883f-11e5-85fb-e41f136aba3e:10115962' /*!*/;# at 559#151222 9:10:19 server id 1026872625 end_log_pos 634 CRC32 0x83a74912 Query thread_id=18 exec_time=0 error_code=0SET TIMESTAMP =1450746619/*!*/;BEGIN/*!*/;# at 634#151222 9:10:19 server id 1026872625 end_log_pos 744 CRC32 0x581f6031 Query thread_id=18 exec_time=0 error_code=0SET TIMESTAMP =1450746619/*!*/;update tb set val = val + 1 where id = 1/*!*/;# at 744#151222 9:10:19 server id 1026872625 end_log_pos 775 CRC32 0x793f8e34 Xid = 6813916COMMIT /*!*/;
这段Binlog从文件120偏移处(Format_description_log_event之后的第一个Binlog Event)开始截取。可以看到,第一个Binlog Event的类型为:Previous-GTIDs,它存在于每个binlog文件中。当开启GTID时,每个binlog文件都有且只有一个Previous-GTIDs,位置都是在Format_description_log_event之后的第一个Binlog Event处。它的含义是在当前Binlog文件之前执行过的GTID集合,可以充当索引用,使用这个Binlog Event,可以便于快速判断GTID是否位于当前binlog文件中。
下面看看gtid_purged和gtid_executed是如何构造的。MySQL在启动时打开最老的binlog文件,读取其中的Previous-GTIDs,那么就是@@global.gtid_purged。MySQL在启动时打开最新的binlog文件,读取其中的Previous-GTIDs,构造一个gtid_set,然后再遍历这个最新的binlog文件,把遇到的每个gtid都添加到gtid_set中,当文件遍历完成时,这个gtid_set就是@@global.gtid_executed。
前面说过只有在@@global.gtid_executed为空的情况下,才可以动态设置@@global.gtid_purged。因此可以通过RESET MASTER的方式来清空@@global.gtid_executed。这一点,类似Ares中的命令:set binlog_group_id=XXX, master_server_id=YYY with reset;(是会删除binlog的) 通过解析上面的binlog文件,我们也可以看到,每个事务之前,都有一个GTID_log_event,用来指定GTID的值。总体来看,一个MySQL binlog的格式大致如下:
我们知道,在未开启GTID模式的情况下,从库用(File_name和File_pos)二元组标识执行到的位置。START SLAVE时,从库会先向主库发送一个BINLOG_DUMP命令,在BINLOG_DUMP命令中指定File_name和File_pos,主库就从这个位置开始发送binlog。
在开启GTID模式的情况下,如果指定MASTER_AUTO_POSITION=1。START SLAVE时,从库会计算Retrieved_Gtid_Set和Executed_Gtid_Set的并集(通过SHOW SLAVE STATUS可以查看),然后把这个GTID并集发送给主库。主库会使用从库请求的GTID集合和自己的gtid_executed比较,把从库GTID集合里缺失的事务全都发送给从库。如果从库缺失的GTID,已经被主库pruge了呢?从库报1236错误,IO线程中断。
主库发送的二进制的事件:主库Executed_Gtid_Set对从库(Retrieved_Gtid_Set U Executed_Gtid_Set)的补集
Retrieved_Gtid_Set:从库已经接收到主库的事务编号
Executed_Gtid_Set:已经执行的事务编号
考虑下面这种情况,有个集群已经在使用GTID模式同步,想给集群增加一台从库,新做完一台从库,数据和主库一致,但是没有binlog,也就是说新从库的@@global.gtid_executed是空的。但是CHANGE MASTER时可以通过File_name和File_pos找到正确的同步点,然后START SLAVE,一切正常。过了一会儿,觉得还可以通过MASTER_AUTO_POSITION = 1的方式重新CHANGE MASTER,然后再START SLAVE。这种情况下,主库一看从库GTID里少了那么多binlog,然后把全部缺失的binglog再给从库发送一遍,那么悲剧就发生了。
为了解决这个问题,新做完从库以后,应该在从库上执行reset master; set global gtid_purged = 'xxxxx',把缺失的GTID集合设置为purged,然后就可以直接使用MASTER_AUTO_POSITION=1自动找点儿了。
由此可见,开启GTID以后,Binlog和数据文件一样重要,不仅要求主从数据一致,还要求主从Binlog中GTID集合一致。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~