MySQL和Redis保持数据一致性的解决方案总结

1.问题起因:

在高并发的业务场景下,数据库的性能瓶颈往往都是用户并发访问过大。一般都会使用缓存技术来减缓数据库压力,让读请求先访问到缓存,在缓存没有的情况下再从数据库中读取,如下图所示,该方法可以有效提升数据库性能。而实现缓存技术往往采用redis,而数据库则如MySQL等。

现有的大部分业务场景下大多采用读写分离的操作来提升数据库吞吐量,但是并发读写访问的时候,对缓存和数据库相互交叉执行操作,则会出现数据不一致问题。

在进行数据更新时,就涉及到先更新缓存还是先更新数据库了,其实两种方式都有数据一致性问题:

举个例子:假如业务A为写请求,业务B为读请求

1.先更新数据库再更新缓存

步骤1:业务A先更新数据库,此时该业务线由于宕机或者其他原因延迟没有继续进行。

步骤2:业务B读取数据,读取的是缓存中的旧数据。

步骤3:业务A恢复过来,更新缓存

可以看到,由于写请求延迟,可能会读到旧的缓存数据。

2.先更新缓存再更新数据库

步骤1:业务A先删除缓存

步骤2:业务B进入,业务B发现缓存中没有数据,直接从数据库中进行读取,读到了数据库中的旧数据

步骤3:业务A更新数据库并返回。

可以看到,由于写请求延迟,可能读到旧的数据库数据。

2.解决方案

我所了解的解决方案主要有以下三种:

(1)读写请求串行化

最为简单的一种方法,写请求在更新之前需要先获得分布式锁,获取到锁才能去更新数据库,获取不到则进行等待,超时直接返回更新失败。更新完数据库后更新缓存,如果更新失败,放到内存队列中进行重新尝试。读请求则同样需要获得锁,然判断缓存中是否有数据,有则直接读缓存,没有则直接读数据库,并更新缓存。

这种方案可以保证数据的一致性。但是会降低系统吞吐量(等待时间长),这在需要数据强一致的情况下适用。(银行转账)

(2)延时双删策略

写请求在更新数据库的前后均删除一次缓存,第二次删除需要延迟一段时间。大致步骤如下:

步骤1:删除缓存

步骤2:更新数据库

步骤3:延迟一定的时间

步骤4:再次删除缓存

步骤4再次删除的原因:可以删除可能在步骤1到2之间被读请求存入的脏数据。

步骤3延迟一定时间的原因

(1)保证步骤1和2之间的读请求正常执行,让步骤4可以有效删除脏数据。

(2)如果数据库是主从模式,从库数据更新需要一定时间,防止读请求在没有缓存的情况下,读出从库中的旧数据放在缓存中。(本质上让步骤4可以也可以有效删除从从库中读出的脏数据)。

(3)基于订阅binlog的同步机制

思路:业务项目直接更新数据库,数据库将更新过程记录下来,把记录通过消息队列,推送更新各台redis服务器,redis服务器根据记录更新自身缓存数据。

实现:

1.MySQL产生新的更新操作(添加,删除等等),就可以把binlog相关消息推送(canal,kafka,rabbitMQ)至缓存服务(Redis),Redis根据binlog中的记录更新自身数据。

扩展:MySQL的主从备份机制也是通过binlog来实现数据的一致性。

  • 3
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值