当前位置:网站首页>字节面试题:如何保证缓存和数据库的一致性
字节面试题:如何保证缓存和数据库的一致性
2022-08-02 05:08:00 【知食份子.】
方案分析
更新缓存策略方式常见的有下面几种:
- 先更新缓存,再更新数据库
- 先更新数据库,再更新缓存
- 先删除缓存,再更新数据库
- 先更新数据库,再删除缓存
下面一一介绍!
方案一:更新缓存,更新数据库
这种方式可轻易排除,因为如果先更新缓存成功,但是数据库更新失败,则肯定会造成数据不一致。
方案二:更新数据库,更新缓存
这种缓存更新策略俗称双写,存在问题是:并发更新数据库场景下,会将脏数据刷到缓存
updateDB();updateRedis();举例:如果在两个操作之间数据库和缓存又被后面请求修改,此时再去更新缓存已经是过期数据了。

方案三:删除缓存,更新数据库
存在问题:更新数据库之前,若有查询请求,会将脏数据刷到缓存
deleteRedis();updateDB();举例:如果在两个操作之间发生了数据查询,那么会有旧数据放入缓存。

该方案会导致请求数据不一致
如果同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么会出现如下情形:
- 请求A进行写操作,删除缓存
- 请求B查询发现缓存不存在
- 请求B去数据库查询得到旧值
- 请求B将旧值写入缓存
- 请求A将新值写入数据库
上述情况就会导致不一致的情形出现。而且,如果不采用给缓存设置过期时间策略,该数据永远都是脏数据。
方案四:更新数据库,删除缓存
存在问题:在更新数据库之前有查询请求,并且缓存失效了,会查询数据库,然后更新缓存。如果在查询数据库和更新缓存之间进行了数据库更新的操作,那么就会把脏数据刷到缓存
updateDB();deleteRedis();举例:如果在查询数据库和放入缓存这两个操作中间发生了数据更新并且删除缓存,那么会有旧数据放入缓存。

假设有两个请求,一个请求A做查询操作,一个请求B做更新操作,那么会有如下情形产生
- 缓存刚好失效
- 请求A查询数据库,得一个旧值
- 请求B将新值写入数据库
- 请求B删除缓存
- 请求A将查到的旧值写入缓存
如果发生上述情况,确实是会发生脏数据。但是发生上述情况有一个先天性条件,就是写数据库操作比读数据库操作耗时更短
不过数据库的读操作的速度远快于写操作的
因此这一情形很难出现。
方案对比
方案1和方案2的共同缺点:
并发更新数据库场景下,会将脏数据刷到缓存,但一般并发写的场景概率都相对小一些;
线程安全角度,会产生脏数据,比如:
- 线程A更新了数据库
- 线程B更新了数据库
- 线程B更新了缓存
- 线程A更新了缓存
方案3和方案4的共同缺点:
不管采用哪种顺序,2种方式都是存在一些问题的:
- 主从延时问题:不管是先删除还是后删除,数据库主从延时可能导致脏数据的产生。
- 缓存删除失败:如果缓存删除失败,则都会产生脏数据。
问题解决思路:延迟双删,添加重试机制,下面介绍!
更新缓存还是删除缓存?
1.更新缓存缓存需要有一定的维护成本,而且会存在并发更新的问题
2.写多读少的情况下,读请求还没有来,缓存以及被更新很多次,没有起到缓存的作用
3.放入缓存的值可能是经过复杂计算的,如果每次更新,都计算写入缓存的值,浪费性能的
删除缓存优点:简单、成本低,容易开发;缺点:会造成一次cache miss
如果更新缓存开销较小并且读多写少,基本不会有写并发的时候可以才用更新缓存,否则通用做法还是删除缓存。
总结
方案问题问题出现概率推荐程度更新缓存 -> 更新数据库为了保证数据准确性,数据必须以数据库更新结果为准,所以该方案绝不可行大不推荐更新数据库 -> 更新缓存并发更新数据库场景下,会将脏数据刷到缓存并发写场景,概率一般写请求较多时会出现不一致问题,不推荐使用。删除缓存 -> 更新数据库更新数据库之前,若有查询请求,会将脏数据刷到缓存并发读场景,概率较大读请求较多时会出现不一致问题,不推荐使用更新数据库 -> 删除缓存在更新数据库之前有查询请求,并且缓存失效了,会查询数据库,然后更新缓存。如果在查询数据库和更新缓存之间进行了数据库更新的操作,那么就会把脏数据刷到缓存并发读场景&读操作慢于写操作,概率最小读操作比写操作更慢的情况较少,相比于其他方式出错的概率小一些。勉强推荐。
推荐方案
延迟双删
采用更新前后双删除缓存策略
public void write(String key,Object data){ redis.del(key); db.update(data); Thread.sleep(1000); redis.del(key); }- 先淘汰缓存
- 再写数据库
- 休眠1秒,再次淘汰缓存
大家应该评估自己的项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上即可。
这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。
问题及解法:
1、同步删除,吞吐量降低如何处理
将第二次删除作为异步的,提交一个延迟的执行任务
2、解决删除失败的方式:
添加重试机制,例如:将删除失败的key,写入消息队列;但对业务耦合有些严重;

延时工具可以选择:
最普通的阻塞Thread.currentThread().sleep(1000);
Jdk调度线程池,quartz定时任务,利用jdk自带的delayQueue,netty的HashWheelTimer,Rabbitmq的延时队列,等等
实际场景
我们有个商品中心的场景,是读多写少的服务,并且写数据会发送MQ通知下游拿数据,这样就需要严格保证缓存和数据库的一致性,需要提供高可靠的系统服务能力。
写缓存策略
- 缓存key设置失效时间
- 先DB操作,再缓存失效
- 写操作都标记key(美团中间件)强制走主库
- 接入美团中间件监听binlog(美团中间件)变化的数据在进行兜底,再删除缓存

读缓存策略
- 先判断是否走主库
- 如果走主库,则使用标记(美团中间件)查主库
- 如果不是,则查看缓存中是否有数据
- 缓存中有数据,则使用缓存数据作为结果
- 如果没有,则查DB数据,再写数据到缓存

注意
关于缓存过期时间的问题
如果缓存设置了过期时间,那么上述的所有不一致情况都只是暂时的。
但是如果没有设置过期时间,那么不一致问题就只能等到下次更新数据时解决。
所以一定要设置缓存过期时间。
边栏推荐
- goroutine (coroutine) in go language
- Detailed explanation of the software testing process (mind map) of the first-tier manufacturers
- Matlab论文插图绘制模板第41期—气泡图(bubblechart)
- Contents of encoding-indexes.js file printed with Bluetooth:
- ELK log analysis system
- Mysql实现乐观锁
- 测试环境要多少?从成本与效率说起
- leetcode每天5题-Day04
- 25K test old bird's 6-year experience in interviews, four types of companies, four types of questions...
- C language: Check for omissions and fill in vacancies (3)
猜你喜欢

ERROR 1045 (28000) Access denied for user 'root'@'localhost'Solution

Matlab论文插图绘制模板第41期—气泡图(bubblechart)

Use the browser's local storage to realize the function of remembering the user name

上海交大牵手淘宝成立媒体计算实验室:推动视频超分等关键技术发展

Introduction to coredns

Features and installation of non-relational database MongoDB

25K测试老鸟6年经验的面试心得,四种公司、四种问题…

对node工程进行压力测试与性能分析

复盘:图像饱和度计算公式和图像信噪(PSNR)比计算公式

软件测试的需求人才越来越多,为什么大家还是不太愿意走软件测试的道路?
随机推荐
Cyber Security Learning - Intranet Penetration 4
kubernetes affinity, anti-affinity, taint, tolerance
Meta公司新探索 | 利用Alluxio数据缓存降低Presto延迟
配合蓝牙打印的encoding-indexes.js文件内容:
Redis database
H5 access payment process - WeChat payment & Alipay payment
非关系型数据库MongoDB的特点及安装
Packaging and deployment of go projects
TikTok平台的两种账户有什么区别?
Shuttle + Alluxio 加速内存Shuffle起飞
复盘:图像饱和度计算公式和图像信噪(PSNR)比计算公式
ApiPost 真香真强大,是时候丢掉 Postman、Swagger 了
Browser onload event
Introduction to Grid Layout
apifox介绍及使用(1)。
PSQL function, predicate, CASE expression and set operations
Detailed installation and configuration of golang environment
测试技术之APP蓝牙连接测试
Stress testing and performance analysis of node projects
Say good woman programmers do testing have an advantage?More than a dozen interview, abuse of cry ~ ~ by the interviewer