Redis--13--缓存一致性问题

news2025/1/20 15:45:19

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 缓存一致性问题
    • 1、先更新缓存,再更新DB
    • 方案二:先更新DB,再更新缓存
    • 方案三:先删缓存,再写数据库
      • 推荐1:==延迟双删==
    • 方案四:先写数据库,再删缓存
  • 删除缓存失败怎么办?
    • 方案一:设置过期时间
    • 方案二:同步重试
    • 方案三:消息队列
    • 方案四:订阅mysql的binlog
    • 总结


缓存一致性问题

通常情况下,我们使用缓存的主要目的是为了提升查询的性能。大多数情况下,是这样使用缓存的:

在这里插入图片描述

当数据库有数据更新时,在很长的一段时间内(决定于缓存的过期时间),用户请求从缓存中获取到的都可能是旧值,而非数据库的最新值。那么,该如何更新缓存呢?目前有以下四种解决方案:

  1. 先更新缓存,再更新数据库(差)

  2. 先更新数据库,再更新缓存(差)

  3. 先删除缓存,后更新数据库(一般)

  4. 先更新数据库,后删除缓存(推荐)

讨论四种方案前先统一两个认知,以便更好理解四种方案:

  • 缓存一致性问题没有绝对可靠的方案,我们只能让两者尽量接近,但无论如何也不能百分百达到一致性效果。
  • 缓存和数据库,无论先处理谁,只要后者有延迟/失败,都会导致不一致的情况,这也正是缓存不一致的根本原因所在。所有解决方案和讨论都是围绕这一点来进行的。

1、先更新缓存,再更新DB

在这里插入图片描述

缺点:如果刚写完缓存,突然网络出现了异常,导致写数据库失败了。这样缓存中的数据就变成脏数据,这个问题非常严重,也是最差的一种解决

方案二:先更新DB,再更新缓存

在这里插入图片描述
缺点一:问题又来了,写数据库成功,但写缓存失败了,依然会造成缓存脏数据的问题。但写缓存失败比写数据库失败的概率要小很多了(因为数据库可能有加锁、外键约束、超时等机制限制),所以此方案要比第一种方案好一点。

  • 如果对接口性能要求不高,还可以把写数据库和写缓存放到一个事务中,写缓存失败就回滚数据库。

缺点二:然而高并发场景下,还会有个棘手问题:
在这里插入图片描述

  • 请求a先过来,刚写完了数据库。但由于网络原因,卡顿了一下,还没来得及写缓存。
  • 这时候请求b过来了,先写了数据库。
  • 接下来,请求b顺利写了缓存。
  • 此时,请求a卡顿结束,也写了缓存。

很显然,在这个过程当中,请求b在缓存中的新数据,被请求a的旧数据覆盖了。

也就是说:在高并发场景中,如果多个线程同时执行先写数据库,再写缓存的操作,可能会出现数据库是新值,而缓存中是旧值,两边数据不一致的情况。

缺点三:浪费系统资源

  • 写的缓存的内容,并不是简单的数据,而是要经过非常复杂的计算或者查询筛选得出的结果,这样每写一次缓存都要计算一次,这是非常浪费系统资源的,尤其对那些写多读少的业务场景,更是雪上加霜。

删除缓存类

方案三:先删缓存,再写数据库

方案一:
在这里插入图片描述

嗯,看起来还不错。即使写数据库失败了,下个请求也会重新触发写缓存操作,基本上避免更新缓存的所有弊端,然而也不是十全十美。

缺点:

在这里插入图片描述

  1. 请求d先过来,把缓存删除了。但由于网络原因,卡顿了一下,还没来得及写数据库。
  2. 这时请求c过来了,先查缓存发现没数据,再查数据库,有数据,但是旧值。
  3. 请求c将数据库中的旧值,更新到缓存中。
  4. 此时,请求d卡顿结束,把新值写入数据库。

这种极端情况下依然会导致写入的缓存为旧值

推荐1:延迟双删

在这里插入图片描述
为了避免方案1的避免,写完数据库后,再删除一次。

该方案有个非常关键的地方是:第二次删除缓存,并非立马就删,而是要在一定的时间间隔之后

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

那么,为什么一定要间隔一段时间之后,才能删除缓存呢?

请求d卡顿结束,把新值写入数据库后,请求c将数据库中的旧值,更新到缓存中。此时,如果请求d删除太快,在请求c将数据库中的旧值更新到缓存之前,就已经把缓存删除了,这次删除就没任何意义。必须要在请求c更新缓存之后,再删除缓存,才能把旧值及时删除了。

还是mysql读写分离的问题
在这里插入图片描述
在这里插入图片描述

方案四:先写数据库,再删缓存

在这里插入图片描述
就怕一种情况:缓存失效。

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

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

  1. 缓存刚好自动失效。
  2. 请求f从数据库查出旧值,更新缓存的耗时,比请求e写数据库,并且删除缓存的耗时还长。

缓存失效。只有可能是查询比删除慢的情况,而这种情况相对来说会少很多。同时结合延时双删的处理,可以有效的避免缓存不一致的情况。

删除缓存失败怎么办?

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

方案一:设置过期时间

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

方案二:同步重试

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

方案三:消息队列

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

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

比如基于 RocketMQ 的可靠性消息通信,来实现最终一致性
在这里插入图片描述

方案四:订阅mysql的binlog

当一条数据发生修改时,MySQL 就会产生一条变更日志(binlog),我们可以订阅这个日志,拿到具体操作的数据,然后再根据这条数据,去删除对应的缓存。
在这里插入图片描述
意思就是我们的业务应用在修改数据时,「只需」修改数据库,无需操作缓存。步骤如下:

  1. 在业务接口中写数据库之后,直接返回成功。
  2. mysql服务器会自动把变更的数据写入binlog中。
  3. binlog订阅者(消费者)获取变更的数据,然后删除缓存
    在这里插入图片描述

在这里插入图片描述

总结

缓存删除比更新效果更好

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

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

删除缓存有两种方式

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

针对缓存一致性要求不是很高的场景,那么只通过设置超时时间就可以了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1280213.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python ctypes:揭秘高级Python与底层交互秘籍

更多资料获取 📚 个人网站:ipengtao.com ctypes是Python标准库中的外部函数库,允许Python调用动态链接库中的函数。它提供了与C兼容的数据类型和允许Python调用共享库中的函数,对系统级编程和与硬件交互非常有用。 基本用法 加…

基于Django框架搭建的协同过滤算法电影推荐网站-爬取的豆瓣电影数据

欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介概述技术栈实现流程 二、功能三、系统四. 总结 一项目简介 # 电影推荐网站介绍 概述 该电影推荐网站是基于Django框架搭建的,旨在为用户提供个…

jdk1.8 hashmap源码阅读

目录 hashmap 成员变量 hashmap支持null键吗?为什么? 当扩容的时候,所有元素都会重新计算hash值吗? 怎么减少扩容次数 为什么node数组的大小是2的n次? 1.8和1.7的区别 1.8为啥要用红黑树? 扩容机制…

12.3_黑马MybatisPlus笔记(上)

目录 02 03 04 05 06 07 ​编辑 thinking:system.out::println?​编辑 thinking:list.of? 08 thinking:RequestParam和 ApiParam注解使用? thinking:RequestParam 和PathVariable的区别? ​编辑 ​编…

“B2B+OMS方案”,赋能家电巨头构建BC订单一体化能力,促进业务增长|徐礼昭

某国际知名家电电器品牌,年营收超过5000亿元。该电器企业其整体业务分三大类:线上线下B2B2C业务、线下B2B业务以及DTC零售业务。 随着业务的发展,该电器品牌对2B业务及DTC业务的数字化系统能力支撑需要更加全面和立体,以适应业务…

Sharding-Jdbc(4):Sharding-Jdbc分库

1 新建数据库 创建ds_0数据库和ds_1数据库,在两个数据库新建表如下: CREATE TABLE t_order (order_id bigint(20) NOT NULL,user_id bigint(20) NOT NULL,PRIMARY KEY (order_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin; 2 新建maven项目…

基于姿态估计的3D动画生成

在本文中,我们将尝试通过跟踪 2D 视频中的动作来渲染人物的 3D 动画。 在 3D 图形中制作人物动画需要大量的运动跟踪器来跟踪人物的动作,并且还需要时间手动制作每个肢体的动画。 我们的目标是提供一种节省时间的方法来完成同样的任务。 我们对这个问题…

SmartSoftHelp8,FrameCode极速二次开发框架源码

1.winform outlook style UI C/S 极速开发框架 netframework 2.0 2.winform toolbar style UI C/S 极速开发框架 netframework 2.0 3.WPF toolbar style UI C/S 极速开发框架 netframework 4.0 4.Xadmin-UI jquery B/S 极速开发框架 5.Vue element UI B/S…

ArrayList 与 顺序表 (附洗牌算法)!

曾经我也是一枚学霸,直到有一天想去学渣的世界看看,结果就找不到回去的路了。 目录 1. 线性表 2.顺序表 2.1 接口的实现 3. ArrayList简介 4. ArrayList使用 4.1 ArrayList的构造 4.2 ArrayList常见操作 4.3 ArrayList的遍历 4.4 ArrayList的扩…

永倍达电商模式分析:创新商业模式引领新时代购物潮

在2019年底,全球新冠疫情席卷,导致大量实体经济倒闭,人们纷纷居家躲避,经济陷入下行,企业家面临倒闭威胁。永倍达成立于2020年,是陕西永倍达电子商务有限公司的品牌,而其母公司实际上是天津铸源…

Stable Diffusion 系列教程 - 1 基础准备(针对新手)

使用SD有两种方式: 本地: 显卡要求:硬件环境推荐NVIDIA的具有8G显存的独立显卡,这个显存勉勉强强能摸到门槛。再往下的4G可能面临各种炸显存、炼丹失败、无法生成图片等各种问题。对于8G显存,1.0模型就不行&#xff0…

前端入门(四)Ajax、Promise异步、Axios通信、vue-router路由、组件库

文章目录 AjaxAjax特点 Promise 异步编程(缺)Promise基本使用状态 - PromiseState结果 - PromiseResult AxiosVue中使用AxiosAxios请求方式getpostput和patchdelete并发请求 Vue路由 - vue-router单页面Web应用(single page web application&…

C++ string类(2)—成员访问、插入、删除、替换、查找和交换操作

目录 一、成员访问 1、[ ]&at 2、front( )&back( ) 二、插入元素 三、删除元素 四、替换元素 五、查找元素 1、查找第一次出现位置 2 、在指定范围内查找 六、交换字符串 七、c_str 八、rfind&substr 一、成员访问 1、[ ]&at 虽然二者功能一样&…

LeetCode | 101. 对称二叉树

LeetCode | 101. 对称二叉树 OJ链接 在本函数里不好进行判断,我们另外定义一个函数来如果两个都相等为空,就返回true一个为空,一个不为空都不为空,就比较值然后递归1的左,2的右,1的右,2的左 bool _isSymm…

javaee实验:MVC 框架技术应用——URL 映射及方法参数的使用

目录 urlmvc框架mvc框架的设计mvc流程 实验目的实验内容实验过程创建项目创建项目结构编写代码简单测试一下 url 和 Hypertext 以及 HTTP 一样,URL 是 Web 中的一个核心概念。它是浏览器用来检索 web 上公布的任何资源的机制 URL 代表着是统一资源定位符&#xff…

《洛谷深入浅出进阶篇》模意义下的乘法逆元+洛谷P3811

什么是乘法逆元? 算数意义上的乘法逆元指的是倒数,即:a*(1/a)1 所以 1/a 是 a在算数意义下的乘法逆元,或者可以说二者互为逆元。 这有什么用呢? 除以a就等于乘上a的乘法逆元,乘以…

keil5 --工程创建

一,文件夹介绍 首先去官网过去其他地方获取到官方提供的标准库文件 下面这个我是在官网进行下载的 我们在打开keil的时候会弹出一个在线下载的框(这个框这里先不做说明,后面在继续讲解),我们不使用这个在线下载功能&a…

LangChain 19 Agents Reason+Action自定义agent处理OpenAI的计算缺陷

LangChain系列文章 LangChain 实现给动物取名字,LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄LangChain 4用向量数据库Faiss存储,读取YouTube的视频文本搜索I…

配置SAP用户密码策略(不用重启服务器的方法)

最近公司审计,给我们提出了要优化密码策略的建议,原因是我们的密码策略太简单了。我稍稍研究了一下。之前是通过RZ10来配置,但是这种方法需要重启服务器,这就比较麻烦。其实有一种方法是通过配置密码策略,不要要重启的…

包装材料ERP是什么?包装材料ERP有什么用

市面上的包装材料种类多种多样,而这些差异化的包装材料对应的产成品规格、型号、质量、销售策略和生产工艺等方面存在诸多差异。 另外,通常包装材料企业的营销渠道比较广泛,不同的销售平台有多样化的业务流程和管理方式,相同的商…