如下图中,gtid set已经分成了无数段。正常情况下我们的从库gtid set应该是不会出现这种大量的空洞的,并且每次都丢失了一个gtid。如果这个时候重做从库,那么会根据gtid的下限去主库拿gtid信息,但是主库先然已经清理了这些gtid信息必然会导致报错。
其实导致出现gap与mysql的bug有直接联系
slave-skip-errors诱因
slave_skip_errors概述
mysql在主从复制过程中,由于各种的原因,从服务器可能会遇到执行binlog中的sql出错的情况,在默认情况下,服务器会停止复制进程,不再进行同步,等到用户自行来处理。
slave-skip-errors的作用就是用来定义复制过程中从服务器可以自动跳过的错误号,当复制过程中遇到定义的错误号,就可以自动跳过,直接执行后面的sql语句。
slave_skip_errors选项有四个可用值,分别为:
off,all,erorcode,ddl_exist_errors
默认情况下该参数值是off,我们可以列出具体的error code,也可以选择all
一些error code代表的错误如下:
1007: 数据库已存在,创建数据库失败
1008: 数据库不存在,删除数据库失败
1050: 数据表已存在,创建数据表失败
1051: 数据表不存在,删除数据表失败
1054: 字段不存在,或程序文件跟数据库有冲突
1060: 字段重复,导致无法插入
1061: 重复键名
1068: 定义了多个主键
1094: 位置线程id
1146: 数据表缺失,请恢复数据库
1053: 复制过程中主服务器宕机
1062: 主键冲突 duplicate entry '%s' for key %d
my.cnf中的写法
slave_skip_errors=1062,1053
slave_skip_errors=all
slave_skip_errors=ddl_exist_errors
该参数为全局静态参数,不能动态调整,可在my.cnf中加入该参数列表后重启mysql服务器生效。
必须注意的是,启动这个参数,如果处理不当,很可能造成主从数据库的数据不同步,在应用中需要根据实际情况,如果对数据完整性要求不是很严格,那么这个选项确实可以减轻维护的成本。
slave-skip-errors=all导致的bug
这个bug存在于8.0.25最新版本(包括老版本),如果我们设置了slave-skip-errors=all参数后,遇到错误后ddl和dml对于gtid的处理不一致。可能导致slave重启失败。
ddl :跳过操作,跳过gtid。gtid 不连续。
dml:跳过操作,但是不跳过gtid。gtid 连续。
数据库版本过低诱因
并没有设置skip-slave-error参数,那么是其他什么bug导致的呢?实际上这个bug是5.7.23以下的版本,并且设置了replicate_wild_do_table等过滤规则会后对create database/alter database/drop database会过滤掉操作,并且从库的gtid也会被抛弃掉,这样就产生了大量的空洞。
测试验证
选择低于5.7.23的一个版本安装主从复制
从库配置表白名单
replicate_wild_do_table=test.t1
版本5.7.20(主库)
server version: 5.7.20-log mysql community server (gpl)
米乐app官网下载 copyright (c) 2000, 2017, oracle and/or its affiliates. all rights reserved.
oracle is a registered trademark of oracle corporation and/or its
affiliates. other names may be trademarks of their respective
owners.
type 'help;' or '\h' for help. type '\c' to clear the current input statement.
mysql> create database test3;
query ok, 1 row affected (0.00 sec)
mysql> show master status\g
*************************** 1. row ***************************
file: mysql-bin.000002
position: 1804
binlog_do_db:
binlog_ignore_db:
executed_gtid_set: 802e82b5-1efa-11ed-9196-5254000a56df:1-9
1 row in set (0.00 sec)
mysql> use test;
reading table information for completion of table and column names
you can turn off this feature to get a quicker startup with -a
database changed
mysql> insert into t1 values(3);
query ok, 1 row affected (0.01 sec)
mysql> show master status\g
*************************** 1. row ***************************
file: mysql-bin.000002
position: 2057
binlog_do_db:
binlog_ignore_db:
executed_gtid_set: 802e82b5-1efa-11ed-9196-5254000a56df:1-10
1 row in set (0.00 sec)
从上面操作可以看到,主库进行create database的操作gtid编号是9,insert到test.t1(也就是我们配置的表白名单)gtid编号是10
版本5.7.20(从库)
mysql> show master status\g
*************************** 1. row ***************************
file: mysql-bin.000003
position: 600
binlog_do_db:
binlog_ignore_db:
executed_gtid_set: 802e82b5-1efa-11ed-9196-5254000a56df:1-3:7-8
1 row in set (0.00 sec)
mysql> show master status\g
*************************** 1. row ***************************
file: mysql-bin.000003
position: 844
binlog_do_db:
binlog_ignore_db:
executed_gtid_set: 802e82b5-1efa-11ed-9196-5254000a56df:1-3:7-8:10
1 row in set (0.00 sec)
主库信息
从库信息
结论很明显,gtid为9的事务被抛弃了,而insert t1的事务传过来了。因此出现了gtid set的gap。
下面是m6米乐安卓版下载官网提供的bug地址
https://bugs.mysql.com/bug.php?id=88891
https://bugs.mysql.com/bug.php?id=91086
处理也很简单,对于出现gap一般都是mysql本身的bug导致
(1)版本低于5.7.23,且需要主从配置replicate_wild_do_table,升级版本即可。
(2)如果版本高于5.7.23,则尽量避免配置slave_skip_errors=all的情况出现。
mysql主从gtid一致,但从库出现gtid set有gap的发生,一定要先检查数据库版本,尽量不使用低于5.7.23版本数据库,对于高于5.7.23版本数据库避免配置主从复制slave-skip-errors=all。