数据库和缓存如何保持一致性

目录

 

前言

更新数据库+更新缓存:

1.在更新缓存前先加一个分布式锁

2.在更新完缓存时,给缓存加上较短的过期时间

Cache Aside策略

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

延迟双删

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

保证两个操作都能执行成功

重试机制

订阅MySQLbinlog,再操作缓存

 总结


前言

由于引入了缓存,那么在数据更新时,不仅要更新数据库,而且要更新缓存,这两个更新操作存在前后的问题:

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

但是会因为并发问题造成缓存和数据库的数据不一致的现象。

如果先更新缓存,在更新数据库:可能会出现下图

缓存和数据库中的数据依然可能不一致。

出现并发问题的时候,当两个请求并发更新同一条数据时,可能会出现缓存和数据库中的数据不一致的现象。 

更新数据库+更新缓存:

如果先更新数据库再更新缓存:可能会出现下图情况

此时,数据库中的数据是 2,而缓存中的数据却是 1,出现了缓存和数据库中的数据不一致的现象

如果业务对缓存命中率有很高的要求,我们也可以采用这个方案。

如何解决这个方式的数据不一致的问题:

1.在更新缓存前先加一个分布式锁

保证同一时间只运行一个请求更新缓存,就不会产生并发问题了,当然引入了锁后,对于写入的性能就会带来影响。

2.在更新完缓存时,给缓存加上较短的过期时间

这样出现缓存不一致的时候,缓存数据也能很快过期,对业务还是能接受的。

Cache Aside策略

不更新缓存,而是删除缓存中的数据,然后到读取数据时,发现缓存中没数据之后,再从数据库中读取数据并更新到缓存中。

写策略与读策略:

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

依然在读写并发时,还是会出现缓存和数据库的数据不一致的问题。

针对读写的并发请求而造成不一致的解决办法是

延迟双删

伪代码:

#删除缓存
redis.delKey(X)
#更新数据库
db.update(X)
#睡眠
Thread.sleep(N)
#再删除缓存
redis.delKey(X)

加了个睡眠时间,主要是为了确保请求 A 在睡眠的时候,请求 B 能够在这这一段时间完成「从数据库读取数据,再把缺失的缓存写入缓存」的操作,然后请求 A 睡眠完,再删除缓存。

所以,请求 A 的睡眠时间就需要大于请求 B 「从数据库读取数据 + 写入缓存」的时间。

但是具体睡眠多久其实是个玄学,很难评估出来,所以这个方案也只是尽可能保证一致性而已,极端情况下,依然也会出现缓存不一致的现象。

因此,还是比较建议用「先更新数据库,再删除缓存」的方案。

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

还是会出现不一致的问题,但这个概率不高,因为缓存的写入通常要远远快于数据库的写入,所以,先更新数据库再删除缓存是可以保证数据一致性的。

还可以给缓存数据加上过期时间,就算在这期间存在缓存数据不一致,经过过期时间,最终还是能达到一致。

但是这个依然会遇到问题:当删除缓存失败时,缓存中的数据依然是旧数据,没有更新。再给缓存加上过期时间后,还要等一段时间才能更新生效的现象。

保证两个操作都能执行成功

通过重试机制订阅MySQL binlog,再操作缓存的方式都可以保证两个操作都能成功。

重试机制

引入消息队列,将第二个操作(删除缓存)要操作的数据加入到消息队列,有消费者来操作数据。

如果应用删除缓存失败,可以从消息队列中重新读取数据,然后再次删除缓存。如果重试超过一定次数还没有成功,就需要向业务层发送报错信息。

如果删除缓存成功,就要把数据从消息队列中移除,避免重复操作。

订阅MySQLbinlog,再操作缓存

先更新数据库,再删缓存」的策略的第一步是更新数据库,那么更新数据库成功,就会产生一条变更日志,记录在 binlog 里。

于是我们就可以通过订阅 binlog 日志,拿到具体要操作的数据,然后再执行缓存删除,阿里巴巴开源的 Canal 中间件就是基于这个实现的。

Canal 模拟 MySQL 主从复制的交互协议,把自己伪装成一个 MySQL 的从节点,向 MySQL 主节点发送 dump 请求,MySQL 收到请求后,就会开始推送 Binlog 给 Canal,Canal 解析 Binlog 字节流之后,转换为便于读取的结构化数据,供下游程序订阅使用。

所以,如果要想保证「先更新数据库,再删缓存」策略第二个操作能执行成功,我们可以使用「消息队列来重试缓存的删除」,或者「订阅 MySQL binlog 再操作缓存」,这两种方法有一个共同的特点,都是采用异步操作缓存。

 总结

数据库和缓存保持一致性:

方式问题解决

先更新缓存,

再更新数据库

数据不一致(并发问题)暂无

先更新数据库,

再更新缓存

同上

1.在更新缓存前加上分布式锁;

2.给缓存加上较短的过期时间。

先删除缓存,

再更新数据库

数据不一致(读写并发)延迟双删

先更新数据库,

再删除缓存

同上

1.重试机制;

2.订阅MySQL binlog,再操作缓存。

 

啊,这个要记好多,回头再来背一遍。

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

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

相关文章

【译】WordPress Bricks主题安全漏洞曝光,25,000个安装受影响

WordPress的Bricks主题存在一个严重的安全漏洞,恶意威胁行为者正在积极利用该漏洞在易受攻击的安装上运行任意PHP代码。 该漏洞被跟踪为CVE-2024-25600(CVSS评分:9.8),使未经身份验证的攻击者能够实现远程代码执行。它影响Bricks的所有版本,包括1.9.6版本及更早版本。 该…

线程变量ThreadLocal用于解决多线程并发时访问共享变量的问题。

ThreadLocal介绍 ThreadLocal叫做线程变量,用于解决多线程并发时访问共享变量的问题。意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建…

如何用生成式人工智能准备和制作吸引人的美食视频?

YouTube是一个全球性的视频分享平台,上面充满了各式各样的内容,其中美食内容因其视觉和味觉上的双重吸引而备受欢迎。作为一个想要进入这个领域的创作者,你需要知道如何准备和制作吸引人的美食视频。以下是一些基本步骤和技巧: 选…

UE4 Niagara 关卡3.4官方案例解析

Texture sampling is only supported on the GPU at the moment.(纹理采样目前仅在GPU上受支持) 效果:textures can be referenced within GPU particle systems。this demo maps a texture to a grid of particles(纹理可以在GPU粒子系统中被引用这个演…

git使用教程14-Pycharm版本控制与分支管理

一、版本控制 1、版本控制介绍 (1)Version Control System 版本控制系统,简称VCS。 (2)版本控制系统分类: 集中式版本控制工具:SVN 分布式版本控制工具:Git 2、Pycharm 支持的版本…

Windows安装MySQL8.0详细步骤

目录 一、官网下载MySQL二、将压缩包解压到没有中文和空格的目录下三、设置配置文件四、配置环境变量五、安装初始化mysql服务 一、官网下载MySQL 进入MySQL官网:https://downloads.mysql.com/archives/community/,下载 Windows (x86, 64-bit), ZIP Arch…

项目管理中,项目经理如何搞定跨部门沟通与协作?

在项目管理中,跨部门沟通是一项至关重要的任务。项目经理作为项目的核心协调者,需要确保不同部门之间的顺畅沟通,以推动项目的顺利进行。项目经理如何搞定跨部门沟通? 实际案例: 某公司正在开发一款智能家居系统&am…

深入探索Docker数据卷:实现容器持久化存储的完美方案(下)

🐇明明跟你说过:个人主页 🏅个人专栏:《Docker入门到精通》 《k8s入门到实战》🏅 🔖行路有良友,便是天堂🔖 目录 四、Docker数据卷的高级管理 1、数据卷的生命周期管理 2、数据…

如何做代币分析:以 CRO 币为例

作者:lesleyfootprint.network 编译:Mingfootprint.network 数据源:CRO Token Dashboard (仅包括以太坊数据) 在加密货币和数字资产领域,代币分析起着至关重要的作用。代币分析指的是深入研究与代币相关…

【Python】进阶学习:pandas--rename()用法详解

【Python】进阶学习:pandas-- rename()用法详解 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程👈 希望得到您的…

基于SpringBoot的物业管理系统

** 🍅点赞收藏关注 → 私信领取本源代码、数据库🍅 本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目希望你能有所收获,少走一些弯路。🍅关注我不迷路🍅** 一 、设计说明 1.1 研究…

Springboot 过滤器、拦截器、全局异常处理

Springboot 过滤器、拦截器、全局异常处理 一 过滤器(Filter) 过滤器是JavaWeb三大组件(Servlet,Filter,Listener)之一。 Filter可以把对资源的请求拦截下来,从而实现一些功能。 注意&#…

低代码工具APEX的入门使用(未包含安装)

第一次使用APEX是2019年,这个技术成名已久只是我了解的比较晚。请看Oracle ACE的网站,这就是用APEX做的。实际上有一次我看O记的人操作他们的办公流程,都是用APEX做的。 那一年,我用APEX做了一个CMDB的管理系统。那时候还没有流行…

美摄科技实时语音数字人解决方案

随着科技的飞速发展,数字人技术已经逐渐渗透到我们生活的各个角落。作为数字人技术的先驱者,美摄科技凭借其卓越的实时语音数字人解决方案,正引领着企业步入一个全新的交互时代。 美摄科技的实时语音数字人解决方案,是基于语音和…

HCIA-Datacom题库(自己整理分类的)_33_DHCP协议多选【7道题】

1.使用动态主机配置协议DHCP分配IP地址有哪些优点? 可以实现IP地址重复利用 工作量大且不好管理 配置信息发生变化(如DNS),只需要管理员在DHCP服务器上修改,方便统一管理 避免IP地址冲突 2.网络中部署了一台DHCP服务器,但是管理员发现部分主机并没有正确获取到该DHCP服务…

产品说明书模板帮你写好了,快来抄作业

想要写好产品说明书,想在网络上参考,信息繁杂且各有不同,东拼西凑也写不出一个好的产品说明书。这时候,如果有产品说明书模板,不仅可以可以提高工作效率,还能保持产品说明书的一致性、提供参考和指导&#…

Mysql删除重复项:力扣196. 删除重复的电子邮箱

题目链接:196. 删除重复的电子邮箱 - 力扣(LeetCode) 题目描述 sql语句 # Write your MySQL query statement below delete a from person as a inner join person as b where a.email b.email and a.id > b.id 思路:内连接…

Windows下JDK下载、配置Java环境变量配置及多个JDK使用

Windows下JDK下载、配置Java环境变量配置及多个JDK使用 1. Windows下配置Java-JDK环境变量 1.1 下载Windows版本JDK 下载地址:(https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) 1.2 Windows下安装JDK 双击进行安装 下一步&#xf…

3.8焕新周什么值得入手?索尼耳机选购指南帮你挑

一年一度的女王节活动即将来临,春暖花开好时候,女生们的购物欲想必也开始蠢蠢欲动。如果想要购入一款降噪耳机,索尼这个品牌是你必须要考虑的选择之一。索尼作为在音频行业耕耘70余年的音频世家,秉持“For The MUSIC为音乐而生”的…

解决uni-app中使用webview键盘弹起遮挡input输入框问题

这个平平无奇的回答&#xff0c;可能是全网最靠谱的解决方案。 这里我用的是vue3 setup .vue文件的方式 <view> <web-view :fullscreen"false" :webview-styles"{top: statusBarHeight40,height:height,progress: {color: green,height:1px } }"…