Redis如何保障缓存与数据库的数据一致性问题?

这篇具有很好参考价值的文章主要介绍了Redis如何保障缓存与数据库的数据一致性问题?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Redis如何保障缓存与数据库的数据一致性问题?

目录

一.最经典的数据库加缓存的双写双删模式

二. 高并发场景下的缓存+数据库双写不一致问题分析与解决方案设计

三、上面高并发的场景下,该解决方案要注意的问题


一.最经典的数据库加缓存的双写双删模式

1.1 Cache Aside Pattern概念以及读写逻辑

(1)读的时候,先读缓存,缓存没有的话,那么就读数据库,然后取出数据后放入缓存,同时返回响应
(2)更新的时候,先删除缓存,然后再更新数据库

1.22、为什么是删除缓存,而不是更新缓存呢?

原因很简单,很多时候,复杂点的缓存的场景,因为缓存有的时候不简单是数据库中直接取出来的值,可能需要比较复杂的计算,甚至进行很多网络请求以及DB请求(比如我们有个缓存就是查微信的公共库以及我们自己的私有库联合组成一个缓存),这种更新缓存的代价很高的,但是呢我们更新完了缓存这个缓存,这个缓存也不一定立马就有人用,可能我更新了很多次数据库更新了很多次缓存都没人访问,这就导致了我服务器做了很多无用的计算

二. 高并发场景下的缓存+数据库双写不一致问题分析与解决方案设计

这里围绕和结合实时性较高的库存服务,把数据库与缓存双写不一致问题以及其解决方案,给大家讲解一下.

我们有两个操作顺序可以选择,其中都存在各种双鞋不一致情况,具体讨论讨论

  • 更新数据先删除缓存,再更新数据库
  • 更新数据先更新数据库,再删除缓存

2.1先删除缓存再更新数据库方式

2.1.1 上面说的最经典的方式有什么缓存不一致的问题?解决方案是什么?

问题:如果我们的方案是先修改数据库库存,再删除缓存,那么如果删除缓存失败了,那么会导致数据库中是新数据,缓存中是旧数据,数据出现不一致。

解决思路:
先删除缓存,再修改数据库,如果删除缓存成功了,如果修改数据库失败了,那么数据库中是旧数据,缓存中是空的,那么数据不会不一致,因为读的时候缓存没有,则读数据库中旧数据,然后更新到缓存中

注意这里无并发读写没问题,但是并发情况下依然会有问题,我们继续往下看

2.2.2 上面第一个解决方案在并发下还是有问题

如果先删除缓存再删除数据库可能存在这种情况

  1. A服务删除缓存成功
  2. B请求来了读旧数据库存
  3. A更新新的库存成功

这样依然是数据库和缓存的库存不一致了

2.3 如何允许短暂的不一致,我们可以用什么思路来做?

2.3.1 基于MQ的分布式事务实现最终一致性

Redis如何保障缓存与数据库的数据一致性问题?

2.3.2 基于binlog监听实现

Redis如何保障缓存与数据库的数据一致性问题?

2.3.3 延迟双删 (比上面稍微优点的一点在于这里不需要印入MQ)

延时双删
延时双删的方案的思路是,为了避免更新数据库的时候,其他线程从缓存中读取不到数据,就在更新完数据库之后,再 Sleep 一段时间,然后再次删除缓存。
Sleep 的时间要对业务读写缓存的时间做出评估,Sleep 时间大于读写缓存的时间即可。
流程如下:
线程1删除缓存,然后去更新数据库。
线程2来读缓存,发现缓存已经被删除,所以直接从数据库中读取,这时候由于线程1还没有更新完成,所以读到的是旧值,然后把旧值写入缓存。
线程1,根据估算的时间,Sleep,由于 Sleep 的时间大于线程2读数据+写缓存的时间,所以缓存被再次删除。

如果还有其他线程来读取缓存的话,就会再次从数据库中读取到最新值。

Redis如何保障缓存与数据库的数据一致性问题?

高并发下又要求强一致性的解决思路:将统一商品的请求进行串行化

Redis如何保障缓存与数据库的数据一致性问题?

三、上面高并发的场景下,该解决方案要注意的问题

3.1读请求长时阻塞

由于读请求进行了非常轻度的异步化,所以一定要注意读超时的问题,每个读请求必须在超时时间范围内返回。

该解决方案,最大的风险点在于说,可能数据更新很频繁,导致队列中积压了大量更新操作在里面然后读请求会发生大量的超时,最后导致大量的请求直接走数据库。

务必通过一些模拟真实的测试,看看更新数据的频繁是怎样的。

因为一个队列中,可能会积压针对多个数据项的更新操作,因此需要根据自己的业务情况
进行测试,可能需要部署多个服务,每个服务分摊一些数据的更新操作。

如果一个内存队列里居然会挤压100个商品的库存修改操作,每隔库存修改操作要耗费10ms
区完成,那么最后一个商品的读请求,可能等待10 * 100 = 1000ms = 1s后,才能得到
数据。

这个时候就导致读请求的长时阻塞。

一定要做根据实际业务系统的运行情况,去进行一些压力测试,和模拟线上环境,去看看
最繁忙的时候,内存队列可能会挤压多少更新操作,可能会导致最后一个更新操作对应的
读请求,会hang多少时间,如果读请求在200ms返回,如果你计算过后,哪怕是最繁忙的
时候,积压10个更新操作,最多等待200ms,那还可以的。

如果一个内存队列可能积压的更新操作特别多,那么你就要加机器,让每个机器上部署的
服务实例处理更少的数据,那么每个内存队列中积压的更新操作就会越少。

其实根据之前的项目经验,一般来说数据的写频率是很低的,因此实际上正常来说,在队
列中积压的更新操作应该是很少的。

针对读高并发,读缓存架构的项目,一般写请求相对读来说,是非常非常少的,每秒的QPS
能到几百就不错了。

一秒,500的写操作,5份,每200ms,就100个写操作。

单机器,20个内存队列,每个内存队列,可能就积压5个写操作,每个写操作性能测试后,
一般在20ms左右就完成。

那么针对每个内存队列中的数据的读请求,也就最多hang一会儿,200ms以内肯定能返回了

写QPS扩大10倍,但是经过刚才的测算,就知道,单机支撑写QPS几百没问题,那么就扩容
机器,扩容10倍的机器,10台机器,每个机器20个队列,200个队列。

大部分的情况下,应该是这样的,大量的读请求过来,都是直接走缓存取到数据的

少量情况下,可能遇到读跟数据更新冲突的情况,如上所述,那么此时更新操作如果先入
队列,之后可能会瞬间来了对这个数据大量的读请求,但是因为做了去重的优化,所以也就
一个更新缓存的操作跟在它后面。

等数据更新完了,读请求触发的缓存更新操作也完成,然后临时等待的读请求全部可以读到
缓存中的数据。

3.2 读请求并发量过高

必须做好压力测试,确保恰巧碰上上述情况的时候,还有一个风险,就是突然间大量读请求会在几十毫秒的延时hang在服务上,看服务能不能抗的住,需要多少机器才能抗住最大的极限情况的峰值。

但是因为并不是所有的数据都在同一时间更新,缓存也不会同一时间失效,所以每次可能也
就是少数数据的缓存失效了,然后那些数据对应的读请求过来,并发量应该也不会特别大。

按99:1的比例计算读和写的请求,每秒5万的读QPS,可能只有500次更新操作。

如果一秒有500的写QPS,那么要测算好,可能写操作影响的数据有500条,这500条数据在
缓存中失效后,可能导致多少读请求,发送读请求到库存服务来,要求更新缓存,这些读
请求每个会hang多长时间?

如果我们写读比例是1:20,每秒更新500条数据,这500秒数据对应的读请求,会有20 * 
500 = 1万,1万个读请求全部hang在库存服务上,就死定了。

3.3 多服务实例部署的请求路由一致性问题

可能这个服务部署了多个实例,那么必须保证,同一个商品id(我们路由到queue的规则),执行数据更新库存操作,以及执行缓存更新操作的请求,都通过nginx服务器路由到相同的服务实例上(这个要改nginx的hash路由规则)

如果一个商品的库存更新操作在A服务器的queue里,他的读路由到另一个服务器的队列里去了,就不需要串行化了。

3.4 热点商品的路由问题,导致请求的倾斜

万一某个商品的读写请求特别高,全部打到相同的机器的相同的队列里面去了,可能造成某台机器的压力过大。

其实只有在商品数据更新的时候才会清空缓存,然后才会导致读写并发,所以更新频率不是太高的话,这个问题的影响并不是特别大,但是的确可能某些机器的负载会高一些,需要注意。

3.5 .串行化缺点

一般来说,就是如果你的系统不是严格要求缓存+数据库必须一致性的话,缓存可以稍微的跟数据库偶尔有不一致的情况,最好不要做这个方案:读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况。

但是呢:串行化之后,就会导致系统的吞吐量会大幅度的降低,用比正常情况下多几倍的机器去支撑线上的请求。


 文章来源地址https://www.toymoban.com/news/detail-420059.html

到了这里,关于Redis如何保障缓存与数据库的数据一致性问题?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 如何保证Redis缓存和数据库的一致性问题

    熟练掌握Redis缓存技术? 那么请问Redis缓存中有几种读写策略,又是如何保证与数据库的一致性问题 今天来聊一聊常用的三种缓存读写策略 首先我们来思考一个问题 写 先更新缓存 再更新数据库 首先如果缓存更新成功但数据库更新失败,会导致数据不一致的问题 其次当请求

    2024年02月14日
    浏览(37)
  • redis的缓存更新策略以及如何保证redis与数据库的数据一致性

    redis的缓存更新策略有这么几种: 1、由应用直接和redis以及数据库相连接:         查询数据时,应用去redis中查询,查不到的话再由应用去数据库中查询,并将查询结果放在redis;         更新数据时,由应用去触发redis数据的删除以及数据库的update。 2、应用只跟redi

    2024年02月13日
    浏览(36)
  • redis实战-缓存数据&解决缓存与数据库数据一致性

    缓存( Cache),就是数据交换的 缓冲区 ,俗称的缓存就是 缓冲区内的数据 ,一般从数据库中获取,存储于本地代码。防止过高的数据访问猛冲系统,导致其操作线程无法及时处理信息而瘫痪,这在实际开发中对企业讲,对产品口碑,用户评价都是致命的;所以企业非常重视缓存技术,

    2024年02月12日
    浏览(37)
  • Redis 原理缓存过期、一致性hash、雪崩、穿透、并发、布隆、缓存更新策略、缓存数据库一致性

    redis的过期策略可以通过配置文件进行配置 redis会把设置了过期时间的key放在单独的字典中,定时遍历来删除到期的key。 1).每100ms从过期字典中 随机挑选20个,把其中过期的key删除; 2).如果过期的key占比超过1/4,重复步骤1 为了保证不会循环过度,导致卡顿,扫描时间上限

    2024年02月08日
    浏览(39)
  • 如何保证缓存和数据库的数据一致性

    若数据库更新成功,删除缓存操作失败,则此后读到的都是缓存中过期的数据,造成不一致问题。 同删除缓存策略一样,若数据库更新成功缓存更新失败则会造成数据不一致问题。 若缓存更新成功数据库更新失败, 则此后读到的都是未持久化的数据。因为缓存中的数据是易

    2023年04月19日
    浏览(39)
  • Redis生产实战-热key、大key解决方案、数据库与缓存最终一致性解决方案

    热 key 问题就是某一瞬间可能某条内容特别火爆,大量的请求去访问这个数据,那么这样的 key 就是热 key,往往这样的 key 也是存储在了一个 redis 节点中,对该节点压力很大 那么对于热 key 的处理就是通过热 key 探测系统对热 key 进行计数,一旦发现了热 key,就将热 key 在 jv

    2024年02月05日
    浏览(37)
  • 如何保证数据库和缓存双写一致性?

    如何保证数据库和缓存双写一致性,是面试中经常被问的一个技术问题,程序汪推荐大家有必要好好研究一波 数据库和缓存(比如:redis)双写数据一致性问题,是一个跟开发语言无关的公共问题。尤其在高并发的场景下,这个问题变得更加严重。 我很负责的告诉大家,该问

    2024年01月18日
    浏览(43)
  • 如何保证缓存与数据库双写时的数据一致性?

    背景:使用到缓存,无论是本地内存做缓存还是使用 Redis 做缓存,那么就会存在数据同步的问题,因为配置信息缓存在内存中,而内存时无法感知到数据在数据库的修改。这样就会造成数据库中的数据与缓存中数据不一致的问题。 共有四种方案: 先更新数据库,后更新缓

    2024年01月24日
    浏览(38)
  • 126、高频Redis面试题:如何保证Redis和数据库数据一致性

    问题:如果数据库中的某条数据放入缓存后,又马上被更新了,那我们应该如何更新缓存 缺点: 如果先更新缓存成功,在更新数据库的时候失败,这时候会导致数据不一致;缓存的作用是不是临时将我们数据保存在内存,便于提高查询速度;但是如果某条数据在数据库中都

    2024年02月13日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包