面试Redis——缓存并发 缓存雪崩 缓存穿透
来源:SegmentFault
时间:2023-02-16 15:36:55 495浏览 收藏
积累知识,胜过积蓄金银!毕竟在##column_title##开发的过程中,会遇到各种各样的问题,往往都是一些细节知识点还没有掌握好而导致的,因此基础知识点的积累是很重要的。下面本文《面试Redis——缓存并发 缓存雪崩 缓存穿透》,就带大家讲解一下MySQL、Redis、Java、数据库、后端知识点,若是你对本文感兴趣,或者是想搞懂其中某个知识点,就请你继续往下看吧~
本文主要叙述缓存并发,缓存雪崩,缓存穿透的问题以及解决方案。
缓存并发
什么是缓存并发
场景:在你每天刷抖音,看微信短视频时,都会有一个评论列表,在评论列表中,查询评论的时候,会先去查询Redis缓存,如果有,就立即返回;如果没,就去数据库查询数据,接着更新缓存,返回数据。这时候,如果访问量非常多,有多个C端同时查询评论,Redis缓存又恰好没缓存数据,此时,多个C端就会同时去查询数据库。上述这种现象,就被称为缓存并发。
话说回来,缓存并发会带来什么危害
- 让数据库的压力剧增,因为数据库抗不了高并发,流量再大一点,可以直接被打垮,对用户极其不友好,在如今互联网上,App应用的被替代率是很高的,稍有不慎,用户就会被其他App抢走,这对企业来说是灾难性的。我们可以知道,Redis这玩意儿,要么不出问题,一出问题,肯定是大问题。这也就是为什么要强调知其然知其所以然的原因。
既然我们已经知道缓存并发的的严重性,那如何解决
- 要解决问题前,我们得分析问题为何会产生。絮叨一下,很多人无论是在面试时或者工作时,遇到问题,就立马改,或者说按照百度给的方法就套上去试,这个不行,试那个。这种解决问题的方式是不正确的。一般解决问题的方法论是:遇到报错——定位问题——分析问题——设计解决方案——解决问题。回到缓存并发问题上,我们分析一下“为什么出现缓存并发”。
为什么会缓存并发
- 原因一:在高并发场景下,机器刚刚启动,且没预热缓存,缓存都为空,又没用分布式锁
- 原因二:在高并发场景下,机器运行已运行一段时间,但缓存刚好失效,又没用分布式锁
- 原因三:在高并发场景下,Redis宕机了
以上3种原因都会产生缓存并发,如有遗漏其他原因,欢迎各位同学在留言区补充。
知道原因后,我们可以对照原因来设计解决方案了。
解决方案
- 针对原因一和原因二,方案 :分布式锁。这个允许一个线程去请求数据库,其他线程挂起,线程查完数据库后,更新缓存,其他线程去访问缓存,返回数据。至于分布式锁如何使用和其底层实现,其实有比较多的细节注意的,但这里不过多讲解,后续会陆续出对应的文章,如果你安耐不住寂寞,可以去谷歌一下。
- 针对原因三,方案:Redis的高可用。说到高可用,无非就是主从结构+哨兵模式,或者Redis集群。(加链接)
分布式锁和Redis高可用,其实是预防措施,这些应该是事前工作。如果现在缓存并发确实已经发生了,能做的就是把这个模块服务的流量入口缩小,以免因这个模块服务流量过大把MySQL直接打死,从而导致其他模块服务受到影响。如果是Redis宕机了,先把流量入口缩小,然后赶紧重启机器。
当然,最好是事前做好Hystrix的限流、降级、拒绝服务等工作。限流和降级,限流,顾名思义就是限制流量,允许多少流量可以通过,比如每秒最多1000。超过1000后的请求,就走降级,比如返回一些默认值或者友情提示:目前系统繁忙,稍后重试。拒绝服务,则是最后一道防线,如果流量持续一段时间后,仍然很大,就直接拒绝服务,拒绝服务是为了保护Redis直接被流量一波带走,如果Redis服务被打死后,恢复是比较耗费时间的,而且也会因为流量一直很大,刚重启,流量一波又直接带走Redis,完成双杀,Double Kill。拒绝服务,会等流量小后,较快恢复回正常服务状态。拒绝服务是迫不得已之举。
当初大头菜初入互联网行业时,乳臭未干,什么也不懂,用Redis前,只知道Redis很厉害,很适合做缓存,关于Redis的注意事项,除了知道在生产环境不能用keys *命令外,其他一概不懂。当时的评论项目,因为流量特别大,并发贼高,查询评论接口就出现了缓存并发问题,幸好提前做了默认值回复和限流+降级措施。下面是用分布式锁解决缓存并发的关键代码:
@Autowired private DistributionLock locker; //没缓存,查数据库,获取评论 if (comment == null) { //加分布式锁,只允许一个线程去回源 if(locker.trylock(Constants.QUERYCOMMENT+moduleType+resourceId)){ try { comment = getDataFromRedis(moduleType, resourceId); if(comment == null){ //缓存没数据,去数据库查 comment = getDataFromMongoDB(moduleType, resourceId); } }finally { locker.unlock(Constants.QUERYCOMMENT+moduleType+resourceId); } }
接下来,继续讲缓存穿透
缓存穿透
什么是缓存穿透
场景:查询评论的时候,如果直接查询id=-1的数据,那么在缓存中,没命中,又去数据库中查找,又没命中。上述这种情况,被称为缓存穿透。用通俗易懂的话来概括:就是查找一个一定不存在数据库的数据,就叫缓存穿透。
那缓存穿透有什么坏处呢
- 如果流量大时,会直接打趴服务,造成服务不可用。
按照方法论的套路继续走
为什么会出现缓存穿透
- 原因一,非正常请求,比如:黑客攻击,专门构造一些特殊格式的数据来请求,给系统造成巨大压力。
- 原因二,正常请求,用户输错了数据。
解决方案
- 方案一:缓存空对象:在请求时,先访问缓存,查不到数据,再去数据库查询,数据库也查不到对应的数据,返回null给客户端。且异步更新缓存(key,“null”),并加入短暂的过期时间。
- 方案二:方案一其实有一个明显的缺点,就是如果请求的数据一定不存在时,那么这个时候,缓存就缓存一大堆无用的(key1,"null"),(key2,"null")。浪费内存。这个时候可以结合数据校验和布隆过滤器。
说到数据校验,这个事儿是特别重要的。尤其是在一些直接涉及到钱的服务中,数据校验是巨重要的。如果不进行数据校验,大公司的老板就少一台宾利。小公司,就可能直接破产了。下面是大头菜的同学所在公司的案例
不管如何,培养良好的开发习惯,能让你受益终身。
缓存雪崩
什么是缓存雪崩
场景:在评论列表中,如果有一批评论成为了热点评论,但不幸,此时这批条评论,在Redis缓存中,都失效了,由于没命中缓存,加上大量请求,都去数据库查询评论,从而给数据库造成极大压力,甚至崩溃。这种情况,被称为缓存雪崩。
缓存雪崩的坏处
给数据库极大压力,甚至打垮数据库,从而造成系统不能正常提供服务。
为什么会缓存雪崩
- 原因一,redis宕机,相当于多个key同一时刻失效。
- 原因二,redis没宕机,多个key正常到时就失效。
总结:如何你面试的时候,遇到这个问题,最好分情况回答,就是redis是否宕机。给面试官留下脑子清晰的印象。
解决方案
- 方案一,解决原因一,既然宕机了,那就想到高可用,redis集群,哨兵模式,故障转移和故障恢复,同时还应该做好监控和报警。如果没法自动完成故障转移,那就人工干预。
- 方案二,过期时间=失效时间+随机时间,解决原因二。
- 方案三,永不过期,既然你是因为过期时间到了导致的雪崩,那就干脆让你不过期就完事了。有人会问,那缓存一致性怎么保证?后台主动更新:就是通过mysql更新的时候,让mq监听Binlog,回调更新缓存。使其缓存和数据库数据保持一致。
- 方案四,可以从应用架构角度出发,通过限流,降级,熔断手段来降低影响,除此之外来避免多级缓存来避免这种灾难。如果你使用的微服务架构是SpringCloud,那你可以直接使用Hystrix,来实现限流,降级,熔断,修改一下配置文件即可。
补充
缓存击穿,就是只有一个key过期的缓存雪崩。
总结
全篇下来,几乎都是按照遇到报错——定位问题——分析问题——设计解决方案——解决问题方法论来写的。文中介绍了缓存并发,缓存穿透,缓存雪崩的定义,危险,原因,解决方案。大头菜希望你读完这篇文章后,不仅能学会知识,更能掌握定位问题——分析问题——解决问题的方法论。知识点,这些以后可能会忘,但方法掌握好后,方能见招拆招。
非常感谢你能看到这里,如果觉得文章写得不错 求关注 求点赞 求分享 (对我非常非常有用)。
如果你觉得文章有待提高,我十分期待你对我的建议,求留言。
如果你希望看到什么内容,我十分期待你的留言。
各位的捧场和支持,是我创作的最大动力!
好了,本文到此结束,带大家了解了《面试Redis——缓存并发 缓存雪崩 缓存穿透》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多数据库知识!
-
499 收藏
-
286 收藏
-
244 收藏
-
235 收藏
-
157 收藏
-
475 收藏
-
266 收藏
-
273 收藏
-
283 收藏
-
210 收藏
-
371 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习