K:缓存数据库双写数据一致性方案
对于缓存和数据库双写,其存在着数据一致性的问题。对于数据一致性要求较高的业务场景,我们通常会选择使用分布式事务(2pc、paxos等)来保证缓存与数据库之间的数据强一致性,但分布式事务的复杂性与对资源的占用问题,使得该处理方式会造成系统性能的降低。对于数据一致性要求没那么高的业务场景,选择分布式事务的处理方式就会显得不是那么必要。为此,在一般情况下,对于数据一致性要求没那么高的业务场景,会选择使用cache-aside-pattern方案来保证缓存与数据库之间,数据的最终一致性,以下文章便是介绍并整理该cache-aside-pattern方案的内容。
对于缓存中的数据,我们提出三个目标:
- 尽可能不将数据库中的旧数据存入缓存中
- 允许缓存中的数据与数据库中的数据存在一小段时间的不一致
- 缓存中的数据与数据库中的数据存在数据不一致的时间应尽量短
对于缓存与数据库的双写问题,无外乎“增删改查” 这四个过程,再考虑进并发的“读读,写写,读写”情况,所有可能的情况组合并不多。为此,我们可以采用穷举的方式对该方案进行说明。
查:
对于数据的查找,该方案的过程与cpu中查找数据的过程是一致的,其过程如下:
- 先查找缓存中的数据,当命中缓存的时候返回数据,查找结束。
- 当没有命中缓存时,查找数据库,对数据库中查找出的相关数据进行处理,之后将相关的数据存入缓存中,查找结束。
其示意图如下:

在考虑高并发查询的情况下,对于该处理过程,如下示意图所示。

当客户端1、客户端2、....、客户端n查询同一数据,且该数据不存在于缓存中时,所有的客户端请求都会去访问数据库,此时会出现缓存击穿的情况,对于缓存击穿的相关问题及解决方案,我们留到下一篇文章再进行讲解。
增:
对于新增数据的情况,我们将数据直接添加进数据库中,且不将新增的数据加载入缓存中,其过程如下示意图所示:

在考虑高并发之时,其过程如下示意图所示:

通过示意图,我们了解到,当采用该种方式新增数据时,在并发情况下,并未出现与我们的目标相违背的问题。
删:
当需要对数据进行删除时,我们有两种删除的方案可供选择。
第一种: 先删除缓存中的数据,再删除数据库中的数据
第二种: 先删除数据库中的数据,再删除缓存中的数据
我们对这两种方案分别进行分析:
先删缓存:
对于先删除缓存中的数据,后删除数据库中的数据这种方案,其示意图如下:

考虑进高并发的情况,当存在读请求和删除数据的请求并发时,由于网络的不可靠和延时问题,其可能出现如下示意图所示的情况:

通过示意图我们了解到,存在着缓存中缓存进已删除的旧数据的情况,这违背了我们提出的第一个目标。
那么,先删除数据库中的数据的情况呢?会出现这样的问题吗?我们接着分析。
先删数据库:
对于先删除数据库中的数据,后删除缓存中的数据这种方案,其示意图如下。

同样考虑进高并发的情况,当存在读请求和删除数据的请求并发时,其发生的情况如下示意图所示:

此时,并未出现与我们的目标相违背的问题。综上,我们在删除数据时,应选择先删除数据库中的数据再删除缓存中的数据的这一方案。
但是该方案仍存在着问题。我们再往下思考,当删除了缓存中的相关数据,此时来了大量读取该数据的请求。这时,就会导致“缓存穿透”问题的出现(该问题同样在下一篇文章中进行讲解)。
改:
当需要对数据进行变更的时候,我们有三种方案可供选择。
第一种: 先更新数据库,后更新缓存
第二种: 先删除缓存,后更新数据库
第三种: 先更新数据库,后删除缓存
我们对这三种方案逐一进行分析。
先更新数据库,后更新缓存:
对于先更新数据库,后更新缓存这种方案,其示意图如下:

考虑高并发的情况,当存在两个更新操作的并发请求时,由于网络的延时问题,其可能会出现如下这种情况:

由上述示意图可知,当存在两个更新操作时,其有将数据库中的旧数据存入缓存中的情况,这违背了我们的第一个目标。那么,有没有办法解决呢?答案是有的,借助乐观锁的相关思想,我们可以给每个数据加上一个版本号,当数据要存入缓存时,比较一下数据的版本号即可。到目前为止,更新了数据库中的相关数据之后,再更新缓存中的数据这个方案看起来是可以的,但是这个方案存在着一个问题,就是需要去更新缓存中的数据,更新缓存中的数据这个操作会影响系统的性能。特别是在写多读少,且缓存的数据不是直接从数据库中存入,而是经过计算之后再进行缓存的业务场景中时,对系统性能造成的影响会更加明显。为此我们可以借助“懒加载”的思想,在更新数据之时,将缓存中的数据进行删除,等到需要用到的时候,才将数据加载进缓存中。下面我们将讨论在更新时删除缓存的两个可能的方案。
先删除缓存,后更新数据库:
对于先删除缓存,后更新数据库的方案,其示意图如下:

考虑高并发的情况,当存在读请求和更新请求并发的情况,由于存在网络延时,其可能出现如下示意图中的情况:

由示意图中的情况可知,在读写并发的情况下,其存在着将数据库中的旧数据存入缓存中的问题。这违背了我们的第一个目标。
先更新数据库,后删除缓存:
对于先更新数据库,后删除缓存的情况,其如下示意图所示:

考虑并发的情况,当存在读请求和更新请求并发,且此时缓存中的数据恰好失效时,再加上由于网络的延迟问题,则有可能会出现如下示意图所示的情况。

由示意图可知,当缓存中的数据恰好失效时,其是可能存在着缓存中存入数据库中的旧数据的可能性的。但是,发生这种情况的概率是比较低的,因为让该种情况出现的条件较为“苛刻”,需要恰好缓存中的数据失效,且要求“读操作”慢于“写操作”。但在通常情况下,“写操作”是慢于“读操作”的,因为写操作一般会涉及到数据库锁的相关操作。
综上,在对比了以上三种方案之后,对于数据更改的情况,我们采用先更新数据库,后删除缓存的方式。

K:缓存数据库双写数据一致性方案的更多相关文章
- 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制
[原创]分布式之数据库和缓存双写一致性方案解析(三) 正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...
- 面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题
今天来分享一下Redis几道常见的面试题: 如何解决缓存雪崩? 如何解决缓存穿透? 如何保证缓存与数据库双写时一致的问题? 一.缓存雪崩 1.1什么是缓存雪崩? 回顾一下我们为什么要用缓存(Redis ...
- (转)面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题
背景:redis问题在面试过程中经常被问到,对于常见问题一定不能放过. 面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题 一.缓存雪崩 1.1什么是缓存雪崩? 如果缓存数据设置的过 ...
- 关于redis的几件小事(八)缓存与数据库双写时的数据一致性
1.Cache aside pattern 这是最经典的 缓存+数据库 读写模式,操作如下: ①读的时候,先读缓存,缓存没有就读数据库,然后将取出的数据放到缓存,同时返回请求响应. ②更新的时候,先删 ...
- Redis使用总结(二、缓存和数据库双写一致性问题)
首先,缓存由于其高并发和高性能的特性,已经在项目中被广泛使用.在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作. 但是在更新缓存方面,对于更新完数据库,是更新缓存呢,还是删除缓存.又或者 ...
- Redis与Mysql双写一致性方案解析
一 前言 首先,缓存由于其高并发和高性能的特性,已经在项目中被广泛使用.在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作 但是在更新缓存方面,对于更新完数据库,是更新缓存呢,还是删除缓存 ...
- 并发中如何保证缓存DB双写一致性(JAVA栗子)
并发场景中大部分处理的是先更新DB,再(删缓.更新)缓存的处理方式,但是在实际场景中有可能DB更新成功了,但是缓存设置失败了,就造成了缓存与DB数据不一致的问题,下面就以实际情况说下怎么解决此类问题. ...
- Redis 多级缓存架构和数据库与缓存双写不一致问题
采用三级缓存:nginx本地缓存+redis分布式缓存+tomcat堆缓存的多级缓存架构 时效性要求非常高的数据:库存 一般来说,显示的库存,都是时效性要求会相对高一些,因为随着商品的不断的交易,库存 ...
- Redis中如何保证数据库和缓存双写时的数据的一致性?
简单的场景: 直接使用 1. 使用Cache Aside pattern 读取的时候,先读取缓存中是否有数据,缓存中没有数据,再去数据库中进行查询,查询出来以后,然后再存入到缓存中 更新的时候,先删除 ...
随机推荐
- 直击 KubeCon 2019 现场,阿里云 Hands-on Workshop 亮点回顾
2019 年 6 月 24 日,KubeCon + CloudNativeCon 第二次在中国举办.此次大会阿里共有 26 个技术演讲入选,并有两场沙龙活动,阿里云专家也与技术极客们也再次相聚.Kub ...
- MUI - 解决弹出输入法时页面高度变小导致底部上浮的问题
解决弹出输入法时页面高度变小导致底部上浮的问题 在有输入框的页面,当输入法弹出的时候,底部元素上浮遮盖了输入框,影响页面美观及功能.查找了一下,页面变窄是不可避免的.即使是设置绝对固定也是不可以的.因 ...
- jquery 即点即改
//在html中建立表单. <table border=""> <th>编号</th> <th>用户名</th> < ...
- python if elif else 区别
if data_ori=='医疗': # 医疗 df = pd.read_excel(path_apply + 'apply/YS_ZY_HZSQ_样例.xls', encoding='gbk', e ...
- iOS 9适配系列教程:后台定位
http://www.cocoachina.com/ios/20150624/12200.html Demo:GitHub地址 [iOS9在定位的问题上,有一个坏消息一个好消息]坏消息:如果不适配iO ...
- 阿里云DataV专业版发布,为可视化创造更多可能!
阿里云数据可视化应用工具DataV正式推出专业版,该版本为可视化领域专业团队和从业者量身打造,定位数据可视分析大屏搭建场景,让使用者可以轻松hold住复杂交互设计和实时数据交互查询需求. 什么是Dat ...
- 「HNOI2015」菜肴制作
「HNOI2015」菜肴制作 这道题想到了其实还挺水的,一开始我直接用小根堆拓扑然后就爆0了,然后我又用十万个堆搜索,T30,还是xkl告诉我要倒着拓扑. 首先要建反图,对于入度为0的点,较小的点先输 ...
- react项目安装及运行
博客地址 :https://www.cnblogs.com/sandraryan/ 安装node ,有就跳过. node.js官网:https://nodejs.org/en/ 终端用node -v ...
- hdu 3662 3D Convex Hull
Problem - 3662 题意很简单,构造三维凸包,求凸包有多少个面. 代码如下: #include <cstdio> #include <iostream> #inclu ...
- Springboot2 Logback mybatis 打印sql执行语句
把这个加入到logback.xml 中就可以打印mysql的日志了 <logger name="jdbc.sqltiming" level="debug" ...