缓存一致性问题解决方案(超全超易懂)

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


1、缓存模型和思路

标准的操作方式就是查询数据库之前先查询缓存,如果缓存数据存在,则直接从缓存中返回,如果缓存数据不存在,再查询数据库,然后将数据存入redis。

缓存作用模型

缓存一致性问题解决方案(超全超易懂)

在项目中我们经常这样用缓存来缓解数据库的压力:

缓存一致性问题解决方案(超全超易懂)

2、缓存更新策略

缓存更新是redis为了节约内存而设计出来的一个东西,主要是因为内存数据宝贵,当我们向redis插入太多数据,此时就可能会导致缓存中的数据过多,所以redis会对部分数据进行更新,或者把他叫为淘汰更合适。

内存淘汰:redis自动进行,当redis内存达到咱们设定的max-memery的时候,会自动触发淘汰机制,淘汰掉一些不重要的数据(可以自己设置策略方式)

超时剔除:当我们给redis设置了过期时间ttl之后,redis会将超时的数据进行删除,方便咱们继续使用缓存

主动更新:我们可以手动调用方法把缓存删掉,通常用于解决缓存和数据库不一致问题

缓存一致性问题解决方案(超全超易懂)

主动更新

  • 删除缓存还是更新缓存?

    • 更新缓存:每次更新数据库都更新缓存,无效写操作较多

    • 删除缓存:更新数据库时让缓存失效,查询时再更新缓存==(选择这个)==

      • 举个例子:如果数据库1小时内更新了1000次,那么缓存也要更新1000次,但是这个缓存可能只在最后一次更新后被读取了1次,那么前999次的更新有必要吗?

        反过来,如果是删除的话,就算数据库更新了1000次,那么也只是做了1次缓存删除(删除前判断key是否存在),只有当缓存真正被读取的时候才去数据库加载

  • 如何保证缓存与数据库的操作的同时成功或失败?

    • 单体系统,将缓存与数据库操作放在一个事务
    • 分布式系统,利用TCC等分布式事务方案
  • 先操作缓存还是先操作数据库?

    • 先删除缓存,再操作数据库
    • 先操作数据库,再删除缓存选择这个

3、两种解决方案

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

先删除缓存,数据库还没有更新成功,此时如果读取缓存,缓存不存在,去数据库中读取到的是旧值,然后更新缓存,缓存不一致发生。如图:

缓存一致性问题解决方案(超全超易懂)

极端情况下会出现缓存不一致问题

  1. 请求A先过来,把缓存删除了。但由于网络原因,卡顿了一下,还没来得及更新数据库。
  2. 这时请求B过来了,先查询缓存发现没数据,再查数据库,有数据,但是旧值。
  3. 请求B将数据库中的旧值,更新到缓存中。
  4. 此时,请求A卡顿结束,把新值写入数据库。
3.1.1延时双删(解决先删除缓存,再更新数据库产生的缓存不一致问题)

上面的问题可以用延时双删的方案来解决,思路是,更新完数据库之后,再sleep一段时间,然后再次删除缓存。

sleep的时间要对业务读写缓存的时间做出评估,sleep时间大于读写缓存的时间即可。

缓存一致性问题解决方案(超全超易懂)

  1. 线程1删除缓存,然后去更新数据库
  2. 线程2来读缓存,发现缓存已经被删除,所以直接从数据库中读取,这时候由于线程1还没有更新完成,所以读到的是旧值,然后把旧值写入缓存
  3. 线程1,根据估算的时间,sleep,由于sleep的时间大于线程2读数据+写缓存的时间,所以缓存被再次删除
  4. 如果还有其他线程来读取缓存的话,就会再次从数据库中读取到最新值
1、什么是延时双删

​ 延迟双删策略是分布式中数据库存储和缓存数据保持一致性的常用策略,但它不是强一致。其实不管哪种方案,都避免不了Redis存在脏数据的问题,只能减轻这个问题,要想彻底解决,得要用到同步锁和对应的业务逻辑层面解决。

2、为什么要进行延迟双删?

一般我们在更新数据库数据时,需要同步redis中缓存的数据,所以存在两种方法:

​ 第一种方案:先执行update操作,再执行缓存清除。

​ 第二种方案:先执行缓存清除,再执行update操作。

这两种方案的弊端是当存在并发请求时,很容易出现以下问题:

第一种方案:当请求1执行update操作后,还未来得及进行缓存清除,此时请求2查询到并使用了redis中的旧数据。

第二种方案:当请求1执行清除缓存后,还未进行update操作,此时请求2进行查询到了旧数据并写入了redis。

3、如何实现延迟双删?

延时双删方案执行步骤
1.删除redis
2.更新数据库
3.延时N秒(N秒的时间要大于一次写操作的时间,一般为3-5秒)
4.删除redis

  • 问题一:为何要延时N秒?
    这是为了我们在第二次删除redis之前能完成数据库的更新操作。
    假象一下,如果没有第三步操作时,有很大概率,在两次删除redis操作执行完毕之后,数据库的数据还没有更新,此时若有请求访问数据,便会出现我们一开始提到的那个问题。
  • 问题二: 为何要两次删除redis?
    如果我们没有第二次删除操作,此时有请求访问数据,有可能是访问的之前未做修改的redis数据,删除操作执行后,redis为空,有请求进来时,便会去访问数据库,此时数据库中的数据已是更新后的数据,保证了数据的一致性。
4、小结
  • 延迟双删用比较简洁的方式实现 mysql 和 redis 数据最终一致性,但它不是强一致。
  • 延迟,是因为 mysql 和 redis 主从节点数据同步不是实时的,所以需要等待一段时间,去增强它们的数据一致性。
  • 延迟是指当前请求逻辑处理延时,而不是当前线程或进程睡眠延迟。
  • mysql 和 redis 数据一致性是一个复杂的课题,通常是多种策略同时使用,例如:延迟双删、redis 过期淘汰、通过路由策略串行处理同类型数据、分布式锁等等。

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

缓存一致性问题解决方案(超全超易懂)

第一种情况

  1. 请求a先写数据库,由于网络原因卡顿了一下,没有来得及删除缓存。
  2. 请求b查询缓存,发现缓存中有数据,直接返回该数据。
  3. 请求a删除缓存。

第二种情况

但如果是读数据请求先过来呢?

  1. 请求b查询缓存,发现缓存中有数据,直接返回该数据。
  2. 请求a先写数据库。
  3. 请求a删除缓存。

这种情况看起来也没问题。

第三种情况

但就怕一种情况:缓存失效。

  1. 缓存自动失效。
  2. 请求a查询缓存,发缓存中没有数据,查询数据库的旧值,但由于网络原因卡顿了,没有来得及更新缓存。
  3. 请求b先写数据库,接着删除了缓存。
  4. 请求a更新旧值到缓存中。

如图所示:

缓存一致性问题解决方案(超全超易懂)

这时,缓存和数据库的数据同样出现不一致的情况了。但这种情况还是比较少的,需要同时满足以下条件:

  • 缓存刚好自动失效。

  • 请求a从数据库查出旧值,更新缓存的耗时,比请求b写数据库,并且删除缓存的耗时还长。

删除缓存失败怎么办?

其实先写数据库,再删缓存的方案,跟缓存双删的方案一样,有一个共同的风险点,即:如果缓存删除失败了怎么办?

方案一:设置过期时间

缓存设置一个过期时间,比如5分钟。当然这种方案只适合数据更新不是太频繁的业务。

方案二:同步重试

在接口中判断是否删除成功,如果失败就重试,直到成功或超过最大重试次数为止,返回数据。当然,这种方案的缺点就是可能影响接口性能。

方案三:消息队列

将删除缓存任务写入mq等消息中间件中,在mq的consumer中处理。但问题也很多:

  1. 引入消息中间件之后,问题更复杂了,对业务代码有一定侵入性、消息丢失怎么办
  2. 消息本身的延迟也会带来短暂的不一致性,不过这个延迟相对来说还是可以接受的

比如基于 RocketMQ 的可靠性消息通信,来实现最终一致性。

缓存一致性问题解决方案(超全超易懂)

方案四:订阅mysql的binlog

我们可以借助监听binlog的消息队列来做删除缓存的操作。这样做的好处是,删除动作无需侵入到业务代码,消息中间件帮你做了解耦,同时,中间件的这个东西本身就保证了高可用。

缓存一致性问题解决方案(超全超易懂)

4、总结

删除缓存有两种方式

  • 先删除缓存,再更新数据库。解决方案是使用延迟双删。

  • 先更新数据库,再删除缓存。解决方案是消息队列或者监听binlog同步,引入消息队列会带来更多的问题,对业务代码有一定侵入性,并不推荐直接使用。

针对缓存一致性要求不是很高的场景,那么只通过设置超时时间就可以了。文章来源地址https://www.toymoban.com/news/detail-411415.html

到了这里,关于缓存一致性问题解决方案(超全超易懂)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Redis生产实战-热key、大key解决方案、数据库与缓存最终一致性解决方案

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

    2024年02月05日
    浏览(49)
  • 博客摘录「 Redis( 缓存篇 ==> 超详细的缓存介绍与数据一致性解决方案 &; 代码实现」

    Redis 旁路缓存 由于高并发原因,先更新数据库和先更新缓存策略都会因为延迟时间而导致数据不一致问题。 两种策略 先删除缓存,再更新数据库; 先更新数据库,再删除缓存。 因为缓存的写入通常要远远快于数据库的写入 ,所以先更新数据库再删缓存,删完缓存,下次访

    2024年02月15日
    浏览(37)
  • Redis数据一致性问题的三种解决方案

    Redis(Remote Dictionary Server ),是一个高性能的基于Key-Value结构存储的NoSQL开源数据库。大部分公司采用Redis来实现分布式缓存,用来提高数据查询效率。 在Web应用发展的初期,系统的访问和并发并不高,交互也比较少。但随着业务的扩大,访问量的提升,使得服务器负载和关系

    2024年02月14日
    浏览(37)
  • redis和数据库的一致性问题的解决方案

    当前没有框架能够保证redis的数据和数据库的完全一致性,所以需要 我们自己在性能和一致性上作取舍。 下图就是两种在redis缓存数据库内容时的使用。 那么如一个节点的两个图: 缓存的生成,是在首次查询或者缓存过期时间到或者缓存被其他业务删除,进而需要在数据库

    2023年04月08日
    浏览(37)
  • clickhouse 数据一致性保障常用解决方案

    对于任何一个数据存储的框架来说,确保数据的一致性都是其非常重要的组成部分,不管是过程中的强一致性,还是最终一致性,都是数据一致性的解决方案,本篇来聊聊clickhouse中的数据一致性问题。 通过查询 CK 官方手册发现,即便对数据一致性支持最好的 Mergetree,也只是

    2024年01月16日
    浏览(52)
  • Redis持久化与一致性解决方案

    怎样去验证我们的Redis缓存是否一定生效了呢? 很简单:如果缓存生效,那么我们每次查询数据是不是先从Redis里面查,那么好,我们先去查第一次,接着去改MySQL里面的数据值,此时再去查第二次,此时如果发现第二次查询到的数据值与与我们改过的MySQL里面的数据值不一致

    2024年02月05日
    浏览(43)
  • Choerodon猪齿鱼平台中的微服务数据一致性解决方案

    众所周知,微服务架构解决了很多问题,通过分解复杂的单体式应用,在功能不变的情况下,使应用被分解为多个可管理的服务,为采用单体式编码方式很难实现的功能提供了模块化的解决方案。同时,每个微服务独立部署、独立扩展,使得持续化集成成为可能。由此,单个

    2024年02月19日
    浏览(38)
  • Spring Boot整合canal实现数据一致性解决方案解析-部署+实战

    🏷️ 个人主页 :牵着猫散步的鼠鼠  🏷️ 系列专栏 :Java全栈-专栏 🏷️ 个人学习笔记,若有缺误,欢迎评论区指正   1.前言 2.canal部署安装 3.Spring Boot整合canal 3.1数据库与缓存一致性问题概述 3.2 整合canel 4.总结 canal [kə\\\'næl]  ,译意为水道/管道/沟渠,主要用途是 基于

    2024年03月19日
    浏览(50)
  • 谷粒商城实战(010 缓存-解决数据一致性问题以及SpringCache的使用)

    Java项目《谷粒商城》架构师级Java项目实战,对标阿里P6-P7,全网最强 总时长 104:45:00 共408P 此文章包含第166p-第p172的内容 缓存一致性问题解决 redisson使用lua脚本,所以的锁都保证了原子性 改之前的代码 锁的粒度越小越好 如11号商品和12号商品 用同一把锁,12的并发也会影响

    2024年04月08日
    浏览(70)
  • Canal框架 Redis和MySQL数据一致性的解决方案 阿里中间件Canal

    MySQL与Redis缓存的同步的两种方案 方案2:解析MySQL的binlog 实现,将数据库中的数据同步到Redis。数据库每一步操作都会写入binlog,通过订阅监听binlog实时感知数据变化,根据数据变化情况删除reids并添加重试机制。 引入消息队列:若Redis删除失败,则将Redis key放入消息队列,消

    2023年04月12日
    浏览(49)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包