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

目录

 

前言

更新数据库+更新缓存:

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.hqwc.cn/news/512000.html

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

相关文章

uniapp制作--简单的tab切换

一、实现思路 在UniApp中&#xff0c;可以使用v-if来控制Tab栏并进行切换。 创建一个方法来控制点击时的效果。 二、实现步骤 ①view部分展示 <!-- tab选项 --><view class"select-area"><view class"select-top"><view clas…

C++入门项目:通讯录管理系统

文章目录 一、步骤拆分1.系统需求2.显示菜单3.添加联系人4.显示联系人5.删除联系人6.查找联系人7.修改联系人8.清空通讯录9.退出功能 二、完整代码&#xff08;200行&#xff09;三、手把手视频教程 一、步骤拆分 1.系统需求 利用C来实现一个通讯录管理系统&#xff0c;系统中…

npm、cnpm、pnpm使用详细

简介&#xff1a; npm&#xff1a;npm&#xff08;Node Package Manager&#xff09;是Node.js的包管理工具&#xff0c;用于安装、更新、卸载Node.js的模块和包。它提供了一个命令行界面&#xff0c;使得开发者可以轻松地管理项目依赖。npm 是 nodejs 中的一部分&#xff0c;…

视频怎么在线转换gif?分享简单一招在线转换

在现在的互联网时代&#xff0c;gif动图已经是非常流行的一种图像格式了。特别是在网络聊天中&#xff0c;能够快速有效的传达情感等。当我们的手中有一些视频素材&#xff0c;想要从中截取gif动画时可使用在线动画制作&#xff08;https://www.gif.cn/&#xff09;工具&#x…

新手想玩硬件,买单片机还是树莓派好?

新手想玩硬件&#xff0c;买单片机还是树莓派好&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#x…

服务器出现故障如何恢复数据?

服务器数据恢复案例之服务器raid6中3块硬盘离线导致阵列崩溃的数据恢复案例 服务器故障&#xff1a; 服务器中有一组由6块盘组建的 RAID6&#xff0c;这台网站服务器上运行MYSQL数据库和存放其它类型的文件。该组raid中有两块磁盘离线&#xff0c;管理员没有及时更换磁盘&#…

基本设计模式

单例模式 ES5 function Duck1(name:string){this.namenamethis.instancenull }Duck1.prototype.getNamefunction(){console.log(this.name) }Duck1.getInstancefunction(name:string){if(!this.instance){this.instance new Duck1(name)} } const aDuck1.getInstance(a) const…

蓝桥杯——123

123 二分等差数列求和前缀和数组 题目分析 连续一段的和我们想到了前缀和&#xff0c;但是这里的l和r的范围为1e12&#xff0c;明显不能用O(n)的时间复杂度去求前缀和。那么我们开始观察序列的特点&#xff0c;可以按照等差数列对序列进行分块。如上图&#xff0c;在求前10个…

unity Game视图看不到贴花,但是在Scene视图能看到

解决方法&#xff1a;找到URP的配置文件 &#xff0c;修改Quality–RederScale为1&#xff0c;就可以了&#xff0c;这是unity 的bug&#xff0c;2022版本以后就没有这个问题了

ES完全入门

1、ES集群节点有哪些主要角色&#xff1f; 1.1、Master 1.2、Data 1.3、Ingest 1.4、Coordination 2、Shard数量的确定

Guitar Pro 8.1中文版永久许可证激活2024最新24位注册激活码生成器

Guitar Pro是一款非常受欢迎的音乐制作软件&#xff0c;它可以帮助用户创建和编辑各种音乐曲谱。从其诞生以来就送专门为了编写吉他谱而研发迭代的。 尽管这款产品可能已经成为全球最受欢迎的吉他打谱软件&#xff0c;在编写吉他六线谱和乐队总谱中始终处于行业领先地位&#…

BERT学习【BERT的例子以及作用】

一、case 1.case1 多输入单输出。通过输入一个句子&#xff08;sequence&#xff09;&#xff0c;然后输出一个句子的分类&#xff08;这个句子是正向还是负向&#xff09;。将句子输入BERT&#xff0c;然后通过softmax输出分类。 2.case2 多输入多输出。输入一个句子&…