重复数据产生原因:分布式锁超时与主从延迟

16 篇文章 0 订阅

背景:

mysql集群,读写分离,一主两从。

 原本的业务(代码)逻辑如下:

问题:但是同一个孩子对同一个题目出现了两条答题结果

5 定位问题

scratch答题数据初始化逻辑: 1)判断是否有该用户的答题数据     2)没有则新插入初始化数据 3)

但是插入的几条记录时间间隔都比较大,所以猜测是记录插入时 mysql和redis等数据存储存在一定的问题。

先看了下redis发现所有数据均正常。

然后查看mysql发现其iops明显增加,如下图:

几乎可以确认是mysql的问题,怎么确认呢?按照代码逻辑一定是先查询后插入,所以想通过mysql的binlog获取信息。

所以到这里问题解决了,插入时间分别是4.11 4.20 4.21 但是都是被阻塞了,执行时间都在几分钟之后。

简单插入一条记录,为什么执行了分钟级别的时间?

这条alter语句,执行了近20分钟,且这个该sql没有阻塞select 但阻塞了inset,所以最终导致insert多次,产生重复答题结果

流程如下:

别的同事新写了一个wiki,说明两条数据是因为读写分离导致的主从延迟,并发现事务不生效,提出的解决方案是增加事务。

总体结论

说明:

1 代码如果实际没有启用事务,读写分离如果有大的延迟的确会导致重复数据。即可能出现主库已经插入,未同步到从库,所以第二个线程查询发现依旧没有数据存在,此时依旧会执行插入

2 如果代码中启用了事务,不存在读写分离的问题,所有的读写都会走主库。所以即使有很大的主从延迟,也不会导致数据的重复。事务中的读写sql都走主库原因如下:

3 启用了事务也不能完全避免重复数据,因为数据库的隔离级别是读已提交,所以仍有可能出现不可重复读  和 幻读的问题,场景如下:

事务1拿到分布式锁,中insert,但是还没提交

alter、大事务等导致事务1被阻塞,事务1的redis分布式锁释放

事务2拿到分布式锁,虽然查的也是主库,因为事务1中还没提交,查询依旧查不到,以为还没有孩子的答题结果,所以会继续insert

事务1中提交

事务2中提交

所以结论:事务只能解决读写分离导致的问题;不能解决分布式锁超时导致的问题。

解决:大SQL业务低峰期执行 + 从硬件、配置、业务层面减小MySQL主从延迟 + 业务唯一索引 +

启用事务,避免多次快速保存导致的重复数据

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值