【搞定面试官】系列:当面试官问你如何保证缓存和数据库双写一致性时,他到底想问什么
来源:SegmentFault
时间:2023-01-21 08:57:16 339浏览 收藏
小伙伴们有没有觉得学习数据库很有意思?有意思就对了!今天就给大家带来《【搞定面试官】系列:当面试官问你如何保证缓存和数据库双写一致性时,他到底想问什么》,以下内容将会涉及到MySQL、Redis、Java,若是在学习中对其中部分知识点有疑问,或许看了本文就能帮到你!
面试开始
小伙子你好,看你简历上写到了MySQL和Redis。今天我们就围绕他们两个展开吧。Redis和MySQL是后端开发中举重若轻的重要角色。实际开发中二者也基本上如影随行,为了提高性能和响应,Redis常常存放热点数据,MySQL存放所有数据,保证数据持久化。所以Redis可以说是MySQL的一部分数据。
那么问题来了,当MySQL中的持久化数据发生改变,如何通知Redis呢?也即如何保证缓存和数据库数据的双写一致性呢?
面试官您好,我们在开发中采取的方案是:先更新数据库,然后删除相应缓存,直到下次请求缓存发现没有数据,再从MySQL中读取,同时将数据更新到Redis。
那为什么采用删除缓存而不是更新缓存呢?
如下图所示,如果采取更新缓存的方式,可能出现请求A先于请求B发生,更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存,这就导致了脏数据。
其次,如果你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用更新缓存的方案就会导致数据压根还没被读取过,但缓存已被频繁的更新,浪费性能。
那先删除缓存,再更新数据库会不会有什么问题?
如下图所示,请求A进行写操作,删除缓存,请求B查询发现缓存不存在,就去数据库查询得到旧值,之后将旧值写入缓存,此时请求A再将新值写入数据库。
这种情况就会导致数据不一致的情形出现。而且,如果不采用给缓存设置过期时间策略,该缓存数据永远都是脏数据。
好的,刚刚说的方案确实在并发环境中都会有问题。那你们采用先更新数据库,再删除缓存,这种方案一定不会出现并发问题吗?
答案是不一定,也可能会出现并发问题。如下图所示,
当步骤Step3的更新数据库操作比步骤Step2的读取数据库操作耗时更短,就有可能使得步骤Step4先于步骤Step5,此时缓存中的就是脏数据。但一般情况下数据库的读操作的速度是远快于写操作的(此点从MySQL的并发读写量就可看出,相同硬件配置下并发读的效率是并发写的数倍)。
因此,如果你想实现基础的缓存和数据库双写一致的逻辑,那么在大多数情况下,在不想做过多设计、增加太大工作量的情况下,请先更新数据库,再删除缓存!
先更新数据库,再删除缓存,除了你刚刚说得问题,还会有别的问题吗?
如果MySQL采用了读写分离架构,当请求A更新数据在master库上并删除了缓存,但此时数据库主从同步还未完成。请求B查询缓存发生Cache miss之后从slave库上读取到的还是旧值,此时也会造成数据不一致。
你刚刚说到先更新数据库,再删除缓存也有可能造成数据不一致,怎么解决呢?
采用延时双删。如下图所示,请求A更新数据库之后,为防止删除缓存先行发生于请求B的将缓存写入旧值,可以通过将请求A更新完数据库之后休眠一会(例如100ms,200ms,根据实际业务场景拟定),再删除缓存,这样基本能保证缓存中存放的不会是脏数据。主从架构也是这个原理,就是请求A在更新master之后不用立即删除缓存,通过延时双删保证主从同步已经完成,最后删除缓存数据。
但你这种方案,请求A休眠一段时间的话,可能会影响到接口的RT,降低系统的吞吐量,如何解决呢?
这里比较优雅的方案是通过异步实现。即开启一个线程池,在请求A的时候开启一个单独的线程,异步的休眠一段时间然后执行缓存删除。当然也可以通过将缓存中相应的key扔到消息队列,通过MQ异步删除,但仅为了异步删除缓存就多加了一层消息队列,可能会造成系统设计更加复杂,并且会带来别的问题。
前面一直有提到删除缓存,如果删除缓存失败了怎么办呢?
再加一个重试机制,保证删除缓存成功。
如果我一定要数据库和缓存数据一致性怎么办?
没有办法做到绝对的一致性,这是由CAP理论决定的,缓存系统适用的场景就是非强一致性的场景,所以它属于CAP中的AP。
CAP理论是分布式系统中的经典理论,即一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。
根据BASE(Basically Available,Soft State和Eventually Consistent)理论,缓存和数据库只能做到数据的最终一致性。
面试结束
时间也不早了,今天就到这里吧,看出来小伙子对这块掌握的比较深入。我们公司就缺少你这种人才,要不现在就签把Offer签了吧。
这个时候你肯定欲绝还迎,一手接Offer一边摆摆手:不行不行,深圳马那边也急着等我给回复呢,催了我好几天了。
面试官一听,payroll组何在,加价!
小结
使用缓存并不是一个很简单的事情,尤其在需要缓存与数据库保持强一致的场景,才知道让数据库数据和缓存数据保持一致性是一门很高深的学问。
从远古的硬件缓存,操作系统缓存开始,缓存就是一门独特的学问。这个问题也被业界探讨了非常久,争论至今也无果,因为其实这是一个权衡的问题。
我是少侠露飞,爱技术,爱分享。
本篇关于《【搞定面试官】系列:当面试官问你如何保证缓存和数据库双写一致性时,他到底想问什么》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于数据库的相关知识,请关注golang学习网公众号!
-
499 收藏
-
286 收藏
-
244 收藏
-
235 收藏
-
157 收藏
-
140 收藏
-
426 收藏
-
363 收藏
-
370 收藏
-
152 收藏
-
368 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 开心的棒棒糖
- 这篇技术文章出现的刚刚好,很详细,真优秀,收藏了,关注作者了!希望作者能多写数据库相关的文章。
- 2023-04-12 09:32:54
-
- 粗暴的帆布鞋
- 太细致了,收藏了,感谢老哥的这篇博文,我会继续支持!
- 2023-03-12 18:05:19
-
- 明理的小伙
- 这篇博文出现的刚刚好,太详细了,很棒,码住,关注博主了!希望博主能多写数据库相关的文章。
- 2023-02-26 00:16:06
-
- 还单身的高跟鞋
- 这篇技术文章真及时,作者大大加油!
- 2023-02-10 17:10:21
-
- 朴实的小丸子
- 好细啊,码起来,感谢up主的这篇文章内容,我会继续支持!
- 2023-01-31 07:01:59
-
- 拼搏的煎饼
- 很有用,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢up主分享技术文章!
- 2023-01-27 18:14:06
-
- 等待的棒棒糖
- 赞 👍👍,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢楼主分享技术文章!
- 2023-01-24 00:11:18