MySQL内核月报 2015.01-MySQL · 捉虫动态· 设置 gtid_purged 破坏AUTO_POSITION复制协议
bug描述
Oracle 最新发布的版本 5.6.22 中有这样一个关于GTID的bugfix,在主备场景下,如果我们在主库上 SET GLOBAL GTID_PURGED = "some_gtid_set",并且 some_gtid_set 中包含了备库还没复制的事务,这个时候如果备库接上主库的话,预期结果是主库返回错误,IO线程挂掉的,但是实际上,在这种场景下主库并不报错,只是默默的把自己 binlog 中包含的gtid事务发给备库。这个bug的造成的结果是看起来复制正常,没有错误,但实际上备库已经丢事务了,主备很可能就不一致了。
背景知识
一) binlog GTID事件
binlog 中记录的和GTID相关的事件主要有2种,Previous_gtids_log_event 和 Gtid_log_event,前者表示之前的binlog中包含的gtid的集合,后者就是一个gtid,对应一个事务。一个 binlog 文件中只有一个 Previous_gtids_log_event,放在开头,有多个 Gtid_log_event,如下面所示
二) 备库发送GTID集合给主库
我们知道备库的复制线程是分IO线程和SQL线程2种的,IO线程通过GTID协议或者文件位置协议拉取主库的binlog,然后记录在自己的relay log中;SQL线程通过执行realy log中的事件,把其中的操作都自己做一遍,记入本地binlog。在GTID协议下,备库向主库发送拉取请求的时候,会告知主库自己已经有的所有的GTID的集合,Retrieved_Gtid_Set + Executed_Gtid_Set,前者对应 realy log 中所有的gtid集合,表示已经拉取过的,后者对应binlog中记录有的,表示已经执行过的;主库在收到这2个总集合后,会扫描自己的binlog,找到合适的binlog然后开始发送。
三)主库如何找到要发送给备库的第一个binlog
主库将备库发送过来的总合集记为 slave_gtid_executed,然后调用 find_first_log_not_in_gtid_set(slave_gtid_executed),这个函数的目的是从最新到最老扫描binlog文件,找到第一个含有不存在 slave_gtid_executed 这个集合的gtid的binlog。在这个扫描过程中并不需要从头到尾读binlog中所有的gtid,只需要读出 Previous_gtids_log_event ,如果Previous_gtids_log_event 不是 slave_gtid_executed的子集,就继续向前找binlog,直到找到为止。
这个查找过程总会停止的,停止条件如下:
找到了这样的binlog,其Previous_gtids_log_event 是slave_gtid_executed子集 在往前读binlog的时候,发现没有binlog文件了(如被purge了),但是还没找到满足条件的Previous_gtids_log_event,这个时候主库报错 一直往前找,发现Previous_gtids_log_event 是空集在条件2下,报错信息是这样的
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.
其实上面的条件3是条件1的特殊情况,这个bugfix针对的场景就是条件3这种,但并不是所有的符合条件3的场景都会触发这个bug,下面就分析下什么情况下才会触发bug。
bug 分析
假设有这样的场景,我们要用已经有MySQL实例的备份重新做一对主备实例,不管是用 xtrabackup 这种物理备份工具或者mysqldump这种逻辑备份工具,都会有2步操作,
SET GLOBAL GTID_PURGED ="xxxx"步骤2是为了保证GTID的完备性,因为新实例已经导入了数据,就需要把生成这些数据的事务对应的GTID集合也设置进来。
正常的操作是主备都要做这2步的,如果我们只在主库上做了这2步,备库什么也不做,然后就直接用 GTID 协议把备库连上来,按照我们的预期这个时候是应该出错的,主备不一致,并且主库的binlog中没东西,应该报之前停止条件2报的错。但是令人大跌眼镜的是主库不报错,复制看起来是完全正常的。
为啥会这样呢,SET GLOBAL GTID_PURGED 操作会调用 mysql_bin_log.rotate_and_purge切换到一个新的binlog,并把这个GTID_PURGED 集合记入新生成的binlog的Previous_gtids_log_event,假设原有的binlog为A,新生成的为B,主库刚启动,所以A就是主库的第一个binlog,它之前啥也没有,A的Previous_gtids_log_event就是空集,并且A中也不包含任何GTID事件,否则SET GLOBAL GTID_PURGED是做不了的。按照之前的扫描逻辑,扫到A是肯定会停下来的,并且不报错。
bug 修复
官方的修复就是在主库扫描查找binlog之前,判断一下 gtid_purged 集合不是不比slave_gtid_executed大,如果是就报错,错误信息和条件2一样 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.
详细的bugfix请看revno: 6211
MySQL · 捉虫动态 · 字符集相关变量介绍及binlog中字符集相关缺陷分析 MySQL字符集相关变量介绍及binlog中字符集相关缺陷分析 MySQL支持多种字符集(character set)提供用户存储数据,同时允许用不同排序规则(collation)做比较。 本文基于MySQL5.7介绍了字符集相关变量的使用,通过例子描述了这些变量具体意义。
MySQL · 捉虫动态 · 信号处理机制分析 在 AliSQL 上面有人提交了一个 bug,在使用主备的时候 service stop mysql 不能关闭主库,一直显示 shutting down mysql …,到底怎么回事呢,先来看一下 service stop mysql 是怎么停止数据库的。配置 MySQL 在系统启动时启动需要把 MYSQL_BASEDIR/support-files 目录下的脚本 mysql.sev
MySQL · 捉虫动态 · event_scheduler 慢日志记错 问题背景 最近遇到了 event_scheduler 在记录慢日志时的一个 bug,在这里分享给大家。 为了方便描述问题,先构造一个简单的 event,如下: delimiter // create event event1 on schedule every 5 second starts now() ends date_add(now(), interval 1 hour) do beg
MySQL · 捉虫动态 · 5.6中ORDER BY + LIMIT 错选执行计划 问题描述 create table t1(id int auto_increment primary key, a int, b int, c int, v varchar(1000), key iabc(a,b,c), key ic(c)) engine = innodb; insert into t1 select null,null,null,null,null; insert into
MySQL · 捉虫状态 · bug分析两例 BUG 1 IN查询结果不对 在mysql5.6.16版本下,构建如下测试用例 CREATE TABLE `a` ( `c1` varchar(512) NOT NULL DEFAULT ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `a` VALUES ( i-28s18atup ),( i-2850jdoa2 ),( i-
db匠 rds内核团队秘密研发的全自动卖萌机. 追加特效: 发数据库内核月报. 月报传送: http://mysql.taobao.org/monthly/
相关文章
- MySQL数据库优化总结
- MySQL 关联表批量修改(数据同步)
- 基于Solr DIH实现MySQL表数据全量索引和增量索引
- mysql 数据库通过拷贝文件恢复方法
- mysql简单的碎片清理脚本
- 读书笔记--SQL必知必会--常用MySQL(MariaDB)命令及示例
- MySQL内核月报 2014.08-MySQL· 参数故事·timed_mutexes
- MySQL内核月报 2014.09-MySQL· 限制改进·GTID和升级
- MySQL内核月报 2014.09-MySQL· 引擎差异·create_time in status
- MySQL内核月报 2014.12-MySQL· 答疑释惑·binlog event有序性
- MySQL内核月报 2014.12-MySQL· 答疑释惑·server_id为0的Rotate
- MySQL内核月报 2014.12-MySQL· 捉虫动态·Opened tables block read only
- MySQL内核月报 2015.01-MySQL · 性能优化· 启用GTID场景的性能问题及优化
- MySQL内核月报 2015.01-MySQL · 捉虫动态· mysql client crash一例
- MySQL内核月报 2015.02-PgSQL · 特性分析· Replication Slot
- MySQL内核月报 2015.03-MySQL · 答疑释惑· 并发Replace into导致的死锁分析
- MySQL内核月报 2015.03-MySQL · 捉虫动态· pid file丢失问题分析
- 数据库内核月报 - 2015 / 05-MySQL · 答疑解惑 · binlog 位点刷新策略
- 数据库内核月报 - 2015 / 07-MySQL · 社区动态 · MySQL内存分配支持NUMA
- 数据库内核月报 - 2015 / 08-MySQL · 社区动态 · MySQL5.6.26 Release Note解读
- 数据库内核月报 - 2015 / 08-MySQL · TokuDB · 疯狂的 filenum++
- ThinkPHP5 (mySQL) 统计各个时间段内的订单量
- PHP中smarty与MYSQL数据库的连接
- mysql中union 查询
- 云图说|云数据库MySQL内核小版本升级全攻略
- python3.6操作mysql
- MySQL的INSERT INTO··· ON DUPLICATE KEY UPDATE使用的几种情况