【redis】redis缓存与数据库的一致性
【redis】redis缓存与数据库的一致性
- 【1】四种同步策略
- 【2】更新缓存还是删除缓存
- (1)更新缓存
- (2)删除缓存
- 【3】先更新数据库还是先删除缓存
- (1)出现失败时候的情况
- 1-先删除缓存,再更新数据库(更新数据库失败了)
- 2-先更新数据库,再删除缓存(删除缓存失败了)
- 3-总结
- (2)没有出现失败时候的情况
- 1-先删除缓存,再更新数据库
- 延时双删解决这个问题
- 如果是读写分离的架构怎么办(强制读主库)
- 删除失败了怎么办?
- 2-先更新数据库,再删除缓存(最优方案)
- 利用消息队列进行删除的补偿
- 【4】总结
【1】四种同步策略
想要保证缓存与数据库的双写一致,一共有4种方式,即4种同步策略:
(1)先更新缓存,再更新数据库;
(2)先更新数据库,再更新缓存;
(3)先删除缓存,再更新数据库;
(4)先更新数据库,再删除缓存。
更新缓存与删除缓存哪种方式更合适?应该先操作数据库还是先操作缓存?
【2】更新缓存还是删除缓存
(1)更新缓存
(1)优点
每次数据变化都及时更新缓存,所以查询时不容易出现未命中的情况。
(2)缺点
更新缓存的消耗比较大。如果数据需要经过复杂的计算再写入缓存,那么频繁的更新缓存,就会影响服务器的性能。如果是写入数据频繁的业务场景,那么可能频繁的更新缓存时,却没有业务读取该数据。
(2)删除缓存
(1)优点
操作简单,无论更新操作是否复杂,都是将缓存中的数据直接删除。
(2)缺点
删除缓存后,下一次查询缓存会出现未命中,这时需要重新读取一次数据库。从上面的比较来看,一般情况下,删除缓存是更优的方案。
【3】先更新数据库还是先删除缓存
(1)出现失败时候的情况
首先,我们将先删除缓存与先更新数据库,在出现失败时进行一个对比:
1-先删除缓存,再更新数据库(更新数据库失败了)
先删除缓存再更新数据库,在出现失败时可能出现的问题:
(1)线程A删除缓存成功,线程A更新数据库失败;
(2)线程B从缓存中读取数据;由于缓存被删,进程B无法从缓存中得到数据,进而从数据库读取数据;此时数据库中的数据更新失败,线程B从数据库成功获取旧的数据,然后将数据更新到了缓存。
(3)最终,缓存和数据库的数据是一致的,但仍然是旧的数据
2-先更新数据库,再删除缓存(删除缓存失败了)
先更新数据库再删除缓存,在出现失败时可能出现的问题:
(1)线程A更新数据库成功,线程A删除缓存失败;
(2)线程B读取缓存成功,由于缓存删除失败,所以线程B读取到的是缓存中旧的数据。
(3)最后线程A删除缓存成功,有别的线程访问缓存同样的数据,与数据库中的数据是一样。
(4)最终,缓存和数据库的数据是一致的,但是会有一些线程读到旧的数据。
3-总结
经过上面的比较,我们发现在出现失败的时候,是无法明确分辨出先删缓存和先更新数据库哪个方式更好,以为它们都存在问题。上述场景出现的问题,应该如何解决呢?都建议采用重试机制解决。
(2)没有出现失败时候的情况
1-先删除缓存,再更新数据库
(1)线程A删除缓存成功;
(2)线程B读取缓存失败;
(3)线程B读取数据库成功,得到旧的数据;
(4)线程B将旧的数据成功地更新到了缓存;
(5)线程A将新的数据成功地更新到数据库。
可见,进程A的两步操作均成功,但由于存在并发,在这两步之间,进程B访问了缓存。最终结果是,缓存中存储了旧的数据,而数据库中存储了新的数据,二者数据不一致。
延时双删解决这个问题
如果是先删缓存、再更新数据库,在没有出现失败时可能会导致数据的不一致。如果在实际的应用中,出于某些考虑我们需要选择这种方式,可以采用延时双删的策略,延时双删的基本思路如下:
(1)删除缓存;
(2)更新数据库;
(3)sleep N毫秒;
(4)再次删除缓存。
public void write(String key, Object data) {Redis.delKey(key);db.updateData(data);Thread.sleep(1000);Redis.delKey(key);
}
阻塞一段时间之后,再次删除缓存,就可以把这个过程中缓存中不一致的数据删除掉。而具体的时间,要评估你这项业务的大致时间,按照这个时间来设定即可。最终保证了数据库和缓存的数据一致
如果是读写分离的架构怎么办(强制读主库)
如果数据库采用的是读写分离的架构,那么又会出现新的问题,如下图:
此时来了两个请求,请求 A(更新操作) 和请求 B(查询操作)
(1)请求 A 更新操作,删除了 Redis;
(2)请求主库进⾏更新操作,主库与从库进行同步数据的操作;
(3)请 B 查询操作,发现 Redis 中没有数据;
(4)去从库中拿去数据;
(5)此时主从同步数据还未完成,拿到的数据是旧数据;
此时的解决办法就是如果是对 Redis 进行填充数据的查询数据库操作,那么就强制将其指向主库进⾏查询。
删除失败了怎么办?
如果删除依然失败,则可以增加重试的次数,但是这个次数要有限制,当超出一定的次数时,要采取报错、记日志、发邮件提醒等措施。
2-先更新数据库,再删除缓存(最优方案)
(1)线程A更新数据库成功;
(2)线程B读取缓存成功;
(3)线程A删除缓存成功。
可见,最终缓存与数据库的数据是一致的,并且都是最新的数据。但线程B在这个过程里读到了旧的数据,可能还有其他线程也像线程B一样,在这两步之间读到了缓存中旧的数据,但因为这两步的执行速度会比较快,所以影响不大。对于这两步之后,其他进程再读取缓存数据的时候,就不会出现类似于进程B的问题了。
利用消息队列进行删除的补偿
先更新数据库,后删除缓存这⼀种情况也会出现问题,比如更新数据库成功了,但是在删除缓存的阶段出错了没有删除成功,那么此时再读取缓存的时候每次都是错误的数据了。
此时解决方案就是利用消息队列进行删除的补偿。具体的业务逻辑⽤语⾔描述如下:
(1)请求 线程A 先对数据库进行更新操作;
(2)在对 Redis 进行删除操作的时候发现报错,删除失败;
(3)此时将Redis 的 key 作为消息体发送到消息队列中;
(4)系统接收到消息队列发送的消息后再次对 Redis 进行删除操作;
但是这个方案会有⼀个缺点就是会对业务代码造成大量的侵入,深深的耦合在⼀起,所以这时会有⼀个优化的方法,我们知道对 Mysql 数据库更新操作后再 binlog 日志中我们都能够找到相应的操作,那么我们可以订阅 Mysql 数据库的 binlog 日志对缓存进行操作。
【4】总结
一般情况下,删除缓存是比更新缓存更优的方案;先更新数据库是比先删除缓存更优的方案;总的来说【先更新数据库,再删除缓存】就是四个策略中影响最小,效果最优的方案。
但是如果需要使用【先删除缓存,再更新数据库】的方案的话,可以使用【延时双删】【读写分离时强制读主库】【重试机制】来解决问题。
如果使用【先更新数据库,再删除缓存】时出现删除缓存失败的情况,可以使用【binlog同步到redis】来解决问题。
相关文章:

【redis】redis缓存与数据库的一致性
【redis】redis缓存与数据库的一致性【1】四种同步策略【2】更新缓存还是删除缓存(1)更新缓存(2)删除缓存【3】先更新数据库还是先删除缓存(1)出现失败时候的情况1-先删除缓存,再更新数据库&…...

XCP实战系列介绍12-基于Vector_Davinci工具的XCP配置介绍(一)
本文框架 1.概述2. EcuC配置2.1 Pdu添加步骤2.2 配置项说明3. Can 模块配置4. CanIf 模块配置4.1 接收帧的Hardware Receive Object配置4.2 接收帧和发送帧的Pdu配置1.概述 在文章《看了就会的XCP协议介绍》中详细介绍了XCP的协议,在《XCP实战系列介绍01-测量与标定底层逻辑》…...

Unity Material详解
一、创建 二、属性 1.Shader:Unity内置了一些shader,用户自定义的shader也在这里出现. Edit: 可以编辑一些shader可编辑的内容,如一些属性. 2.Rendering Mode:渲染模式 Opaque-不透明-石头适用于所有的不透明的物体Cutout-镂空-破布透明度只有0%和100…...

碰撞检测算法分类
包围形法粗糙检测, 包含以下两种类检测外接圆法轴对齐包围矩形, AABB 碰撞检测算法之包围形法分离轴精细检测 BOX vs PolygonOBBseparating Axis Theorem碰撞检测算法之分离轴定理GJKGJK(Gilbert–Johnson–Keerthi), 相比 SAT 算法ÿ…...
代码随想录第十二天(
文章目录232. 用栈实现队列补充知识——Deque232. 用栈实现队列 答案思路: 在push数据的时候,只要数据放进输入栈就好,但在pop的时候,操作就复杂一些,输出栈如果为空,就把进栈数据全部导入进来࿰…...

电源模块 DC-DC直流升压正负高压输出12v24v转±110V±150V±220V±250V±300V±600V
特点效率高达80%以上1*2英寸标准封装电源正负双输出稳压输出工作温度: -40℃~85℃阻燃封装,满足UL94-V0 要求温度特性好可直接焊在PCB 上应用HRA 1~40W系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为:4.5~9V、9~18V、及18~36VDC标准&…...

【动画图解】这个值取对了,ViewPager2才能纵享丝滑
前言 在前两篇文章中,我们通过一张张清晰明了的「示意图」,详细地复盘了RecyclerView「缓存复用机制」与「预拉取机制」的工作流程,这种「图解」创作形式也得到了来自不同平台读者们的一致认可。 而从本文开始,我们将正式进入Vi…...

CSDN每日一练:小豚鼠搬家
题目名称:小豚鼠搬家 时间限制:1000ms内存限制:256M 题目描述 小豚鼠排排坐。 小艺酱买了一排排格子的小房子n*m,她想让k只小豚鼠每只小豚鼠都有自己的房子。 但是为了不浪费空间,她想要小房子的最外圈尽量每行每列都有…...
Dockerfile命令及实践构建一个网站
dockerfile用于构建docker镜像的,部署一个用于运行你所需的容器环境。相当一个脚本,通过dockerfile自己的指令,来构建软件依赖、文件依赖、存储、定制docker镜像的方式有两种:手动修改容器内容,导出新的镜像基于Docker…...

[VMware]Ubuntu18.04 网络图标消失
Ubuntu 18.04 网络图标消失运行环境问题解决NO.1 执行 sudo systemctl stop network-managerNO.2 执行 sudo rm /var/lib/NetworkManager/NetworkManager.stateNO.3 执行 sudo systemctl start network-managerNO.4 vi /etc/NetworkManager/NetworkManager.confNO.5 执行 sudo …...
国产C2000,P2P替代TMS320F280049C,独立双核32位CPU,主频高达400MHz
一、特性参数 1、独立双核,32位CPU,单核主频400MHz 2、IEEE 754 单精度浮点单元 (FPU) 3、三角函数单元 (TMU) 4、1MB 的 FLASH (ECC保护) 5、1MB 的 SRAM (ECC保护&…...

二十五、Gtk4-多线程分析
1 回顾 1.1 Gnome相关 首先回顾一下GLib,GObject,GIO,Gtk的不同,因为下面会涉及到这些概念里面的函数。 所有这些都是由Gnome项目开发的库,一般都用于Gnome环境相关的应用程序。 Gtk:GUI界面库。GLib&a…...

JVM基础学习
JVM分为两个子系统,两个组件一个子系统是Class loader类装载系统,另一个子系统是Execution Engine执行引擎一个组件是Runtime data area 运行时数据区,Native Interface 本地接口Class loader:根据给定的全限定类名来装载class文件到运行时数…...

ASML逆袭史:人、资金、技术,缺一不可
前言 近年来,由于众所周知的原因,荷兰ASML(阿斯麦)公司的先进半导体制造设备——光刻机,进入普通大众视野,成为人们茶余饭后谈论的焦点话题之一。 1月底,“美日荷三方谈判达成协议,可…...

MongoDB 覆盖索引查询
MongoDB 覆盖索引查询 官方的MongoDB的文档中对覆盖查询做了说明: 所有的查询字段是索引的一部分所有的查询返回字段在同一个索引中 由于所有出现在查询中的字段是索引的一部分, MongoDB 无需在整个数据文档中检索匹配查询条件和返回使用相同索引的查询…...

Flink Checkpoint 中的Aligned Checkpoint 和 Unaligned Checkpoint
文章目录知识点反压CheckpointBarrierAligned CheckpointUnaligned Checkpoint核心思想实现原理UC同步阶段UC异步阶段知识点 反压 反压是流式系统中关于处理能力的动态反馈机制,并且是从下游到上游的反馈,一般是在实时数据处理的过程中,上游…...

C++快速入门
本章内容我将结合C语言一起,初步学习了解c,与大家一起快速入门这门语言。当然鉴于c本身属于一门中级语言,大家对编程有一定了解之后来学习这门知识会更加得心应手。简介C 被认为是一种中级语言,它综合了高级语言和低级语言的特点。…...
ubuntu18.04 network有线网络图标缺失解决记录
先按照博客1安装驱动 博客1链接:Ubuntu安装 Realtek R8125 驱动_Lwang2018的博客-CSDN博客_瑞昱8125 for ubunt 安装完成后,遇到问题:ifconfig -a显示的有线网接口(名字以en开头)没有ip地址…...

java对象克隆和面向对象的设计原则
java进阶注解内置注解元注解自定义注解对象克隆浅克隆深克隆java设计模式建模语言类之间的关系依赖关系关联关系单向关联双向关联自关联聚合关系组合关系继承关系实现关系面向对象设计原则单一职责开闭原则里氏替换原则依赖倒置接口隔离迪米特原则组合/聚合复用原则注解 java注…...
传透式血氧仪设计方案
该方案一种检测方式是选择使用光敏二极管接收光信号,采用传统穿透式夹指测量;另一种是使用光谱传感器接收光信号,采用反射式测量。该传感器可将光信号直接转换成数据信息给主控端进行处理,从而节省了用户将光信号转换成模拟信号&a…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...

Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...

ui框架-文件列表展示
ui框架-文件列表展示 介绍 UI框架的文件列表展示组件,可以展示文件夹,支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项,适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...