转载

MySQL案例-奇怪的duplicate primary

-------------------------------------------------------------------------------------------------记录文---------------------------------------------------------------------------------------------------------------

结论先行: 最终只是解决了这个问题, 没有找到根本的原因, 本文只有针对这个问题的分析和思考;
现象:
在Master-5.0.X与Slave-5.7.17进行同步的时候, slave worker抛出了一个错误, duplicate primary;
错误信息如图:
MySQL案例-奇怪的duplicate primary

分析:
看上去是个很正常的报错, 主键重复, 出现这个这个问题的可能性有不少, 不过这次的问题比较蹊跷,
因为这个slave是用mydumper新做的, 刚开始同步几条数据就报错, 有点奇怪;

看了一眼表的数据, pk=13的记录确实存在, 那么久看看relaylog, 找一下完整的语句;
找到这个语句以后, 发现事情有点不对(ノへ ̄、)
MySQL案例-奇怪的duplicate primary

由于使用了auto_increment作为主键, binlog会在记录这类语句的时候在binlog的statement之前注明主键的具体值;
从binlog的内容来看, 这个语句明显不应该是插入pk=13的记录, 应该是91391才对;

那么如果从Master把这条数据单独导出来, 直接手动导入的话, 跳过这个错误, 也是能解决问题;
看了一眼relaylog, 到导出数据的时候, 都没有再对这条数据进行修改, let's go~
PS: 因为Master的写入很少, 所以才能这么干, 繁重业务的话, 就跳过这种办法吧...

为了保险起见, 新建了一个测试库, 先试一下这么导数据会不会有问题;
MySQL案例-奇怪的duplicate primary

把数据导进去看看;
MySQL案例-奇怪的duplicate primary

导入没有问题, 而且数据内容也ok, 那么把数据往同步的库里面导入试试.......

MySQL案例-奇怪的duplicate primary

(ノへ ̄、)看样子同步报错并不是意外.....

后来还陆陆续续做过以下尝试:
怀疑表有问题, 毕竟从5.0.X的库导入到5.7.17, 所以尝试了: alter表; mysql_upgrade; 检查auto_increament的值;
怀疑使用了假的relaylogㄟ( ▔, ▔ )ㄏ : 重新做同步;
语句有问题(╯‵□′)╯︵┻━┻  : 从已经有这条数据的测试库直接用insert...select来插入数据; 
MySQL案例-奇怪的duplicate primary

全部都没有用~

最后才把疑点放到这张表的触发器上;
这个触发器是用来做表字符集转换的, 以前在别的数据库中也用到过,这次报错的信息也不是触发器的内容,按道理来说应该是没啥问题的;
不过除了触发器, 好像真没有什么有可能会出问题的地方了, 试着删了这个触发器之后, 发现一切正常了......

最后的解决方法就只能删了所有的触发器;

思考:
首先遇到这个问题的时候, 去查了relaylog, 第一时间的猜测是binlog的问题或者是表的问题,
因为从报错信息里面可以看出来, sql_thread在重演这一条语句的时候, 认为pk=13, 但是binlog里面记录的明显是91391;
那么就有可能是sql_thread在这一块event的时候, 没有认出来这个insert_id=91391的信息, 直接忽略掉了(虽然binlog都是v4, 但是天知道有什么bug不是..),
用了系统自己的auto_increament计数值(因为Master的写入量很少, 考虑到13这个值也不大, 所以产生这种猜测);

所以检查了表的auto_increament值, 也尝试了mysql_upgrade和alter重建表, 但是都没用;

之后发现binlog是statement, 这个语句并没有把所有列的值进行显式的赋值, 而且和后面的另外一条语句组成了一个事务,
如果把完整的信息都列出来, 或者把这个语句拆出来做成一个单独的事务, 是不是就没问题了?
所以之后单独把那一行数据导出来, 再尝试插入到表里面, 不管是source sql文件还是insert...select也不行;
从这几次尝试之后, 基本也能判断不是SQL的问题了;

最后才把注意力放到触发器上面, 这是测试表和业务表唯一的区别, 但是报错里面的信息完全和触发器没关系;
不过在这次出问题的表上, 还是有一些端倪显示出触发器可能有问题, 那就是表自己记录的auto_increament值,
表里面的最大值是91390, 插入失败的数据是91391, 表中记录的auto_increament是91392;
但是发现自己对这方面的了解不多, 也没办法确定这个auto_increament的值是不是查找根本原因的切入点;
路漫漫..... _(:з」∠)_ 

PS: 源库导出结构的时候, 已经确认源库没有触发器和存储过程, 而且也可以确认5.0.X和5.7的binlog都是v4;

PPPPPPPPPS: 毕竟从5.0.X往5.7做同步不是一个常见的场景, 姑且就当做是跨版本的同步问题吧, 如果能换成row模式的话, 好想看看会不会出问题;
正文到此结束
Loading...