|MySQL的这个Bug,坑了多少人?( 三 )


难道是用户对这两种表的访问方式不一样?抓取用户的sql语句 , 果然 , 前两种表用的都是replace into操作 , 最后一种表用的是update操作 。 难道是replace into语句导致的问题?搜索官方bug, 又发现了一个疑似bug 。
bug #87861: “Replace into causes master/slave have different auto_increment offset values”
原因:
(1) Mysql对于replace into实际是通过delete + insert语句实现 , 但是在ROW binlog格式下 , 会向binlog记录update类型日志 。 Insert语句会同步更新autoincrement , update则不会 。
(2) replace into在Master上按照delete+insert方式操作 ,autoincrement就是正常的 。 基于ROW格式复制到slave后 , slave机上按照update操作回放 , 只更新行中自增键的值 , 不会更新autoincrement 。
因此在slave机上就会出现max(id)大于autoincrement的情况 。 此时在ROW模式下对于insert操作binlog记录了所有的列的值 , 在slave上回放时并不会重新分配自增id , 因此不会报错 。 但是如果slave切master , 遇到Insert操作就会出现”Duplicate key”的错误 。
(3) 由于用户是从5.6迁移到5.7 , 然后直接在5.7上进行插入操作 , 相当于是slave切主 , 因此会报错 。
解决方案
业务侧的可能解决方案:
(1) binlog改为mixed或者statement格式
(2) 用Insert on duplicate key update代替replace into
内核侧可能解决方案:
(1) 在ROW格式下如果遇到replace into语句 , 则记录statement格式的logevent , 将原始语句记录到binlog 。
(2) 在ROW格式下将replace into语句的logevent记录为一个delete event和一个insert event 。
心得
(1) autoincrement的autoinc_lock_mode及auto_increment_increment这两个参数变化容易导致出现重复的key , 使用过程中要尽量避免动态的去修改 。
(2) 在碰到线上的问题时 , 首先应该做好现场分析 , 明确故障发生的场景、用户的SQL语句、故障发生的范围等信息 , 同时要对涉及实例的配置信息、binlog甚至实例数据等做好备份以防过期丢失 。
只有这样才能在找官方bug时精准的匹配场景 , 如果官方没有相关bug , 也能通过已有线索独立分析 。
作者:腾讯数据库技术
【|MySQL的这个Bug,坑了多少人?】来源:cloud.tencent.com/developer/article/1367681


推荐阅读