查看原文
其他

高并发场景下缓存与数据库双写,不一致问题及解决方案

Java精选 2022-08-09

>>号外:关注“Java精选”公众号,回复“面试资料”,免费领取资料!Java精选面试题”小程序,3000+ 道面试题在线刷,最新、最全 Java 面试题!

一、缓存与数据库不一致情况
在一般的网站的架构中,我们都会采用缓存架构来抗住高并发场景下的读请求。那么对于写请求,先更新缓存还是先更新数据库?
本文以商品库存信息为例,我们展开讨论,假设刚开始数据库库存=100,缓存中库存=100。
1、先更新数据库,后更新缓存
这种情况下,当需要更新库存的时候,先更新数据库中的库存=99,然后再更新缓存=99。
但是想象一种场景,由于网络原因,数据库更新成功,但是缓存更新失败,那么此时来了读请求,那么此时会读到缓存中的数据,与数据库中的数据不一致,那么就会产生错误。
2、先更新缓存,后更新数据库。
使用该策略,当需要更新库存的时候,先更新缓存中库存=99,然后再更新数据库=99。
此时假设更新完缓存之后,由于网络原因,数据库还没有更新成功,但是此时有一个写请求过来,去缓存中请求数据得到的是更新之后的数据,然而数据库中还是之前的数据,这样就产生了不一致性的问题。虽然这种不一致性情况有些牵强,有人认为,写请求在前,读请求在后,虽然数据库此时没有更新成功,但是一旦网络恢复就会更新成功,与之前读到的是一致的,那么我们暂且认为这种情况也可以行得通。
那么来看看该方案下的另一种情况,如果此时有大量的写请求,每次写请求都需要更新缓存,然后更新数据库,假设10ms中有10个写请求,但是只有一个读请求,需要更新10次缓存和10次数据库。这样在高并发场景下会给系统带来很大的延迟。那么,这种方案真的可行吗?真的是更新吗?
3、先删除缓存,后更新数据库
这里要强调删除,而不是更新,我们可以看到上面一种情况在高并发场景下根本不适用,先删除缓存,之前需要更新10次缓存,10次数据库,我们优化为只需要删除一次缓存,更新10次数据库,当有一个读请求过来只是没有命中,去数据库读取一下,这样对性能的影响也不是很大。
那么,再次思考一下,这样做在高并发情况下真的可以保证数据库和缓存中数据一致吗?
在高并发场景下,当一个写请求过来之后,我们删除了缓存,还没有更新数据库,紧接着来了一个读请求,发现缓存中的数据被删除了,去数据库中读取数据后返回给用户,同时也更新到缓存。在这一系列请求结束之后,写请求才将数据库的数据更新到最新值,此时数据不一致性的问题。
二、高并发场景下的优化方案
在上面,我们主要发现最主要的问题是数据库没有更新成功,读请求就直接读数据库了。那么我们是否可以让读请求在写请求完成之后再去读数据库呢?
1、消息队列串行化方案
该方案的主要思路是在后台进程中我们可以创建多个队列,然后根据hash算法将写请求路由到不同的队列中,当来读请求的时候,就加入队列中,当写请求处理完毕后,再去处理读请求。
该方案需要注意以下几点:
1)可能会有大量读请求,这样读请求不就串行化了?因此只需要将第一个读请求加入队列中,其他读请求阻塞在cache。
2)需要将同一份数据的写请求和读请求路由到同一个队列中。
这种情况下,如果对于同一份数据有多个写请求同时在队列中,那么来一个读请求中加入队列中之后,一般写请求耗时比较久,那么读请求会需要很久才能返回。也许是缓存中根本没有,我们只需直接去数据库中读取即可,但是加入队列中却需要等待这么长时间。
因此,我们可以设置读请求在队列中的等待超时时间,当达到一定时间时还在等待,那么直接去数据库读取返回即可。
以上是本人对缓存数据库不一致情况的理解,本人能力有限,如有问题还望包含,也欢迎指正。谢谢!

作者:不清不慎

blog.csdn.net/qq_37142346/article/details/89463081
往期精选  点击标题可跳转

一张 900w 的数据表,16s 执行的 SQL 优化到 300ms?

一个依赖组件搞定 Spring Boot 反爬虫、接口防盗刷!

都 2021 年了,你还在用 Jenkins ?赶快尝试这 13 种替代方案吧!

Spring Framework 使用时常犯的十大错误,切记不要犯!

Java 中如何优雅的实现对外接口,需要注意哪些事项?

Spring Boot 框架中如何使用 AOP 防止重复提交?(附源码)

Google 出品 Java 编码风格规范,强烈推荐,权威又科学!

Spring Cloud 项目中实现推送消息到 RabbitMQ 消息中间件

程序员网站 Stack Overflow 被收购!以后“抄代码”难道要付费了?

为什么阿里规范需要在 @Transactional 事务注解中指定 rollbackFor?

点个赞,就知道你“在看”!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存