10 缓存双写一致性之更新策略探讨

news/2024/11/25 9:41:10/

什么是缓存双写一致性

  • 如果redis中有数据:需要和数据库中的值相同
  • 如果redis中无数据:数据库中的值要是最新值

缓存按照操作来分,有细分2种

  • 只读缓存
  • 读写缓存
    • 同步直写策略:写缓存时也同步写数据库,缓存和数据库中的数据⼀致;
    • 对于读写缓存来说,要想保证缓存和数据库中的数据⼀致,就要采⽤同步直写策略

数据库和缓存一致性的几种更新策略

  • 挂牌报错,凌晨升级:单线程,这样重量级的数据操作最好不要多线程
  • 目的:总之,我们要达到最终一致性!
    • 给缓存设置过期时间,是保证最终一致性的解决方案。
    • 我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可。也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存,达到一致性,切记以mysql的数据库写入库为准。
    • 上述方案和后续落地案例是调研后的主流+成熟的做法,但是考虑到各个公司业务系统的差距,不是100%绝对正确,不保证绝对适配全部情况,请同学们自行酌情选择打法,合适自己的最好。

我们讨论3种更新策略

先更新数据库,再更新缓存

  • 先更新mysql的某商品的库存,当前商品的库存是100,更新为99个。
  • 先更新mysql修改为99成功,然后更新redis。
  • 此时假设异常出现,更新redis失败了,这导致mysql里面的库存是99而redis里面的还是100 。
  • 上述发生,会让数据库里面和缓存redis里面数据不一致,读到脏数据

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

异常问题
  1. A线程先成功删除了redis里面的数据,然后去更新mysql,此时mysql正在更新中,还没有结束。(比如网络延时)B突然出现要来读取缓存数据。
    在这里插入图片描述
  2. 此时redis里面的数据是空的,B线程来读取,先去读redis里数据(已经被A线程delete掉了),此处出来2个问题:
    • B从mysql获得了旧值:B线程发现redis里没有(缓存缺失)马上去mysql里面读取,从数据库里面读取来的是旧值。
    • B会把获得的旧值写回redis :获得旧值数据后返回前台并回写进redis(刚被A线程删除的旧数据有极大可能又被写回了)。
    • 在这里插入图片描述
  3. A线程更新完mysql,发现redis里面的缓存是脏数据
    • 两个并发操作,一个是更新操作,另一个是查询操作,A更新操作删除缓存后,B查询操作没有命中缓存,B先把老数据读出来后放到缓存中,然后A更新操作更新了数据库。
    • 于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的,而且还一直这样脏下去了
总结流程
  1. 请求A进行写操作,删除缓存后,工作正在进行中…A还么有彻底更新完
  2. 请求B开工,查询redis发现缓存不存在
  3. 请求B继续,去数据库查询得到了myslq中的旧值
  4. 请求B将旧值写入redis缓存
  5. 请求A将新值写入mysql数据库
    上述情况就会导致不一致的情形出现。
    在这里插入图片描述
  • 如果数据库更新失败,导致B线程请求再次访问缓存时,发现redis里面没数据,缓存缺失,再去读取mysql时,从数据库中读取到旧值
解决方案
复习阿里内部缓存击穿的方案
  • 多个线程同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个 互斥锁来锁住它。
  • 其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。
    后面的线程进来发现已经有缓存了,就直接走缓存。
    在这里插入图片描述
采用延时双删策略

在这里插入图片描述

  • 加上sleep的这段时间,就是为了让线程B能够先从数据库读取数据,再把确实的数据写入缓存,然后,线程A再进行删除。所以,线程A sleep的时间,就需要大于线程B读取数据再写入缓存的时间。
  • 这样一来,其他线程读取数据时,会发现缓存缺失,所以会从数据库中读取最新值。因为这个方案会在第一次删除缓存值后,延迟一段时间再次进行删除,所以我们也把他叫做“延迟双删”。
双删方案面试题
  • 这个删除该休眠多久呢?

    • 线程Asleep的时间,需要大于线程B读取数据再写入缓存的时间。
    • 在业务程序运行的时候,统计下线程读数据和写缓存的操作时间,自行评估自己的项目的读数据业务逻辑的耗时,以此为基础来进行估算。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上加百毫秒即可。
    • 这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。
  • 当前演示的效果是mysql单机,如果mysql主从读写分离架构如何?

    • 请求A进行写操作,删除缓存
    • 请求A将数据写入数据库了,
    • 请求B查询缓存发现,缓存没有值
    • 请求B去从库查询,这时,还没有完成主从同步,因此查询到的是旧值
    • 请求B将旧值写入缓存
    • 数据库完成主从同步,从库变为新值 上述情形,就是数据不一致的原因。还是使用双删延时策略
    • 只是,睡眠时间修改为在主从同步的延时时间基础上,加几百ms
  • 这种同步淘汰策略,吞吐量降低怎么办?

    • 在这里插入图片描述

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

异常问题

在这里插入图片描述

业务指导思想
  • 老外论文
  • 知名社交网站facebook也在论文《Scaling Memcache at Facebook》中提出
  • 我们上面的canal也是类似的思想:上述的订阅binlog程序在mysql中有现成的中间件叫canal,可以完成订阅binlog日志的功能。
解决方案

在这里插入图片描述

  1. 可以把要删除的缓存值或者是要更新的数据库值暂存到消息队列中(例如使用Kafka/RabbitMQ等)。
  2. 当程序没有能够成功地删除缓存值或者是更新数据库值时,可以从消息队列中重新读取这些值,然后再次进行删除或更新。
  3. 如果能够成功地删除或更新,我们就要把这些值从消息队列中去除,以免重复操作,此时,我们也可以保证数据库和缓存的数据一致了,否则还需要再次进行重试
  4. 如果重试超过的一定次数后还是没有成功,我们就需要向业务层发送报错信息了,通知运维人员。

总结

方案2和方案3用那个?利弊如何

  • 在大多数业务场景下,我们会把Redis作为只读缓存使用。假如定位是只读缓存来说,理论上我们既可以先删除缓存值再更新数据库,也可以先更新数据库再删除缓存,但是没有完美方案,两害相衡趋其轻的原则
  • 个人建议是,优先使用先更新数据库,再删除缓存的方案。理由如下:
    • 先删除缓存值再更新数据库,有可能导致请求因缓存缺失而访问数据库,给数据库带来压力,严重导致打满mysql。
    • 如果业务应用中读取数据库和写缓存的时间不好估算,那么,延迟双删中的等待时间就不好设置。
  • 多补充一句:如果使用先更新数据库,再删除缓存的方案:如果业务层要求必须读取一致性的数据,那么我们就需要在更新数据库时,先在Redis缓存客户端暂存并发读请求,等数据库更新完、缓存值删除后,再读取数据,从而保证数据一致性。
    在这里插入图片描述

http://www.ppmy.cn/news/221474.html

相关文章

GreatSQL 8.0.32-24 今日发布

1.新增特性 1.1 SQL兼容性1.2 MGR1.3 性能优化1.4 安全 2.稳定性提升 3.其他调整 4.bug修复 5.GreatSQL VS MySQL 6.GreatSQL Release Notes GreatSQL 8.0.32-24版本发布,增加并行load data、(逻辑 & CLONE)备份加密、MGR读写节点可绑定…

音视频编程ffmepg中的关键术语与概念:深度解析与实践

1. 音视频编程基础(Basics of Audio and Video Programming) 1.1 音频和视频的基本概念(Basic Concepts of Audio and Video) 在我们开始深入探讨音视频编程的关键术语和概念之前,首先让我们回到基础,理解…

有的笔记本电脑,可以做工作站什么意思?

1定义 工作站是一种高端的通用微型计算机。 它是为了单用户使用并提供比个人计算机更强大的性能,尤其是在图形处理能力,任务并行方面的能力。 通常配有高分辨率的大屏、多屏显示器及容量很大的内存储器和外部存储器,并且具有极强的信息和高…

一文搞懂KMP算法!!!

一文搞懂KMP算法!!! 🍁什么是KMP算法?🍁什么是 next() 数组 和 前缀表?前缀表有什么作用呢最长公共前后缀如何计算前缀表 🚀 构造next数组🚀 使用next数组来做匹配 🍁什么是KMP算法…

闲鱼买的显卡用什么软件测试,二手折腾记 篇三:我从闲鱼上买到了一张不存在的显卡,RX 5900XT 拆解评测...

创作立场声明:产品为闲鱼自购,希望各位值友喜欢 这件事情要从我上班摸鱼在厕所刷闲鱼说起。 ▲坐在马桶上打开闲鱼想找找有没有 Intel 11 代 QS 的 CPU,结果在老卖家的闲鱼上看到这个,一张伊拉克成色的 RX5900XT,正常关注 PC 的用户都知道这个命名规则是 AMD 的显卡,但是…

12.4 换了一套散热装备,噪音小了

昨天购买了好几个散热器,包括超频三旋风f92的9厘米机箱风扇12元、超频三珊瑚海显卡散热器22元、另外还有一些北桥散热器花无缺,电源风扇f82等等,不过都没用上。 显卡散热方案一共是12225邮费,39块钱。虽然感觉贵了一些&#xff0c…

计算机组装常见问题,组装电脑常见错误有哪些 组装电脑常见错误汇总【详细介绍】...

今天主要讨论一些组装电脑基础的内容,那些高端MOD毕竟只是小众群体。DIY组装电脑,简单说来就是把一堆硬件拼凑,组成一个完整的主机。而组装电脑其中,处理器、 板卡、内存等都是不太容出现问题的。一是由于产品规格严谨&#xff0c…

diy计算机组装注意事项,电脑DIY常见误区有哪些 电脑组装新手注意事项

电脑DIY常见误区有哪些? 玩 家们都知道,CPU分为盒装和散装,盒装带有散热器,可是这个自带的散热器散热效果十分一般,如果是入门级的CPU还好,不过玩家们入手的是高端CPU或 玩玩超频,那么还是在额外选择一款散…