mysql从库gtid间隙问题

来源:这里教程网 时间:2026-03-01 16:52:26 作者:
今天遇到一个关于从库gtid有间隙的问题
问题1:发现从库的gtid集合存在间隙,是什么原因产生的!
一、问题现象,如下所示:
mysql> show slave  status\G
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table: emp.%
Replicate_Wild_Ignore_Table:
Master_UUID: 192cb19f-1a3e-11ed-a619-005056b6e3a1
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Retrieved_Gtid_Set: 192cb19f-1a3e-11ed-a619-005056b6e3a1:1- 421996  #你设置了只同步个别库,但是也是全量拉取binlog,所以这里是连续的!
Executed_Gtid_Set: 192cb19f-1a3e-11ed-a619-005056b6e3a1:1-419859:419861-421996,   #应用的时候可能有间隙!
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)
mysql>
二、问题分析:
主库执行了:create database  compattarn_yl; 但是从库设置Replicate_Wild_Do_Table: emp.%,选择只同步emp库,所以从库在应用relay log的时候,没有应用create database  compattarn_yl,于是选择跳过,进而产生了一个间隙,原因是你没有设置库级别的过滤,如果你设置的是Replicate_Do_DB或者Replicate_Ignore_DB这类库级别的过滤,这个时候你create database的时候,就不会产生间隙了!
三、问题解决:把间隙设置一个空事务,补进slave的gtid集合中
1、停止slave进程
mysql> STOP SLAVE;  只要停止stop  sql thread即可!
2、设置事务号,事务号从Retrieved_Gtid_Set获取,前面的所示间隙为: 192cb19f-1a3e-11ed-a619-005056b6e3a1:419860
在session里设置gtid_next,即跳过这个GTID,
mysql> SET @@SESSION.GTID_NEXT= ' 192cb19f-1a3e-11ed-a619-005056b6e3a1:419860'
3、设置空事物
mysql> BEGIN; COMMIT;
4、恢复事物号
mysql> SET SESSION GTID_NEXT = AUTOMATIC;
5、启动slave进程
mysql> START SLAVE;
问题2,如果从库产生了gtid间隙,那么当你在从库上reset slave all,从新change的时候,就可能会有问题!
一、问题描述:
因为某个原因从库应用gtid的时候产生了间隙,那么当你需要切换master的时候,例如从change master1切换到change master2,这个时候你需要在从库执行如下操作:
1)stop slave;
2) reset slave  all ;
3)change  master to  master2;
4)start slave;
但是发现报错:如下所示
mysql> show slave  status\G
*************************** 1. row ***************************
Slave_IO_Running: No
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Seconds_Behind_Master: 0
Last_IO_Errno: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name: master_21115
Master_TLS_Version:
1 row in set (0.00 sec)
二、问题分析:
因为当你第一次change to  ,并且start slave的时候,slave会把他自己的执行过的gtid集合(也就是SET @@GLOBAL.GTID_PURGED的gtid集合 )发送给master,并和master执行过的gtid集合做对比,然后找到差异的,这时候就会把间隙也当做差异,slave会认为差异的gtid也需要从master拉取对应的binlog, 但是这个binlog已经被master purge了,不存在了,于是就报错了 the master has purged binary logs containing GTIDs that the slave requires;
注意如果你是正常的stop slave+start slave,那么这个时候slave不会尝试去找间隙的gtid,因为他relay log中已经有所有的gtid,所以不需要从新拉一次binlog了,而reset slave all会清空所有的relay log;
三、 解决办法:去掉从库间隙,不去master再要这个gtid了
方法1:直接设置一个空事务即可,推荐使用;
1、停止slave进程
mysql> STOP SLAVE;  只要停止stop  sql thread即可!
2、设置事务号,事务号从Retrieved_Gtid_Set获取,前面的所示间隙为: 192cb19f-1a3e-11ed-a619-005056b6e3a1:419860
在session里设置gtid_next,即跳过这个GTID,
mysql> SET @@SESSION.GTID_NEXT= ' 192cb19f-1a3e-11ed-a619-005056b6e3a1:419860'
3、设置空事物
mysql> BEGIN; COMMIT;
4、恢复事物号
mysql> SET SESSION GTID_NEXT = AUTOMATIC;
5、启动slave进程
mysql> START SLAVE;
方法2:
1)stop slave;
2)在从库查看当前gtid的集合,发现从库应用主库的gtid集合有间隙(gid= 419860),如下所示
show  master  status;
192cb19f-1a3e-11ed-a619-005056b6e3a1:1-419859:419861-421802,
3)reset  master ;
4) 去掉间隙,改成如下所示的样子,
SET @@GLOBAL.GTID_PURGED=' 192cb19f-1a3e-11ed-a619-005056b6e3a1:1-421802';
5)start slave;
题外话:
1、如果主库执行了reset master;
那么从库需要执行reset slave  all,然后从新change下,否则报错找不到master的binlog, 因为主库reset master会清空binlog文件,并且binlog序号从1开始!所以slave需要reset slave  all
2、如果master包含两个gtid,一个是实时用的,一个是静态的或者说是无用的,
如下所示:
MySQL [(none)]> show master  status\G
*************************** 1. row ***************************
File: mysql-bin.002969
Position: 229787697
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 09029e35-2fe0-11eb-a5b5-7cd30ae00c02:1-3,     #这个是由于某种原因产生的一个无用的gtid,或者说静态gtid
712270d9-9864-11eb-8f3f-7cd30ac477f4:1-2478794562  #这个是本实例实时写入的gtid,每写一个事务,该gtid就会加1
这个时候,如果你需要搭建从库,需要保证在slave上设置SET @@GLOBAL.GTID_PURGED=master的两个gtid,否则slave也会报错 the master has purged binary logs containing GTIDs that the slave requires, 除非master当前写的binlog中包含另一个静态gtid全部事务,换句话说就是只会在当前写的binlog文件中去找是否有slave需要的那个静态gtid集合,如果有就拉取,如果没有就报错;但是如果slave需要找的是实时用的gtid事务,这个事务没有在当前写的binlog文件中,这时候不会报错,他会去之前的binlog文件中找到需要的gtid;
3、relay_log_recovery参数
Enables automatic relay log recovery immediately following server startup. The recovery process creates a new relay log file, initializes the SQL thread position to this new relay log, and initializes the I/O thread to the SQL thread position. Reading of the relay log from the master then continues.
现在我们考虑一个问题,假设当从库意外宕机后,同时从库的relay log也一起损坏了,而主库的日志已经传到了从库,只是从库还没有来得及应用这些日志,那么从库该如何处理?
1) 在从库中将relay_log_recovery不设置或者设置为off,如果碰到上面的情形,从库会丢失那些没有应用的日志,主从会不一致。
2)在从库中将relay_log_recovery设置为on,假如果碰到上面的情形,从库会自动放弃所有未执行的relay log,重新生成一个relay log,并将从库的io线程的position重新指向新的relay log。并将sql线程的position退回到跟io线程的position保持一致,重新从新的postion开始拉取binlog并开始同步,( 其实就是从crash时应用的binlog点位开始从新再次拉取binlog,然后sql线程回退到这个点位)这样在从库中事务不会丢失。这个参数建议开启。

相关推荐