一、背景
前两天,有同事反馈,调用我们这边的获取全局唯一ID的接口,得到了重复的id。
二、问题跟踪
查看接口日志,发现出现正确返回前,id是五万多,出问题的后,id突然下降到了301。两条相邻的日志如下:
Apr 20, 2022 @ 14:16:52.824
Apr 20, 2022 @ 14:28:01.198
这样看来,是在下午14:28, 生成的id就出现了异常,比上一个id差距非常大。
查看接口逻辑,是通过replace into 一直修改表里的一条记录,实现生成唯一id的逻辑,具体如下。
replace into的特性如下:
1、replace根据UNIQUE约束的字段(设置为Primary Key),确定被替换的是哪一条记录。如果不存在要替换的记录, 那么就会插入一条新的记录。
2、replace语句会删除原有的一条记录, 并且插入一条新的记录来替换原记录。
再结合接口传参,sep一直传的是个定死的参数,且有唯一索引,那么接口是通过replace into来实现表里一直只存了一条记录,并且主键id会自增。 那么为啥出问题了呢?
由于以前从来没有使用过replace into, 直接在度娘查了下“replace into出现auto_increment回退”, 刚好看到这位大神的文章,跟我们的现象基本一模一样:INSERT ON DUPLICATE KEY UPDATE与 REPLACE 语句简介 | 五块的博客
从这位大神的经验,说是由于主从库切换直接引起这个问题,切换到从库的时候,从库的auto_increment同主库的不一致。
和DBA沟通后,确认我们当天下午14:19左右,腾讯云对此数据库进行了主从切换。
那么切换后,为啥会存在auto_increment不一致呢?我们来一起建个表看看
1、建表
2、插入一条数据,此时
此时的auto_increment:
3、执行 replace into pqj_text values(null,'a');
查看其auto_increment:
可以看到加1
如果从库更新时,也是执行replace into的话, auto_increment肯定和主库一模一样,但是现在出现了差异,那么从库执行的sql是咋样的呢? 找到DBA给出binglog,发现是update,那么从库是执行的update语句。(下图binlog是引用的别的博主截图)
那么我们试试,直接执行update 语句,会更新auto_increment吗?
4、执行update
在刚刚的测试基础上,执行以下sql
update pqj_text
set id= 10
where sep='a'
再来查看其auto_increment:
结果还是3!!没有增加。那么就能看出问题所在了。
当主库执行replace into ,主库的auto_increment一直在增加。
从库通过binlog里的update语句,一直在更新主键id, 但是auto_increment没有改变。
当主从切换后,会从以前的从库auto_incremant自增,导致生成了以前已经出现过的id!!!
三、解决办法
(未完待续)