教你快速吃透缓存穿透、缓存雪崩及缓存击穿
来源:51cto
时间:2023-01-19 21:11:36 494浏览 收藏
大家好,今天本人给大家带来文章《教你快速吃透缓存穿透、缓存雪崩及缓存击穿》,文中内容主要涉及到Redis、缓存击穿、缓存穿透,如果你对数据库方面的知识点感兴趣,那就请各位朋友继续看下去吧~希望能真正帮到你们,谢谢!
一、介绍
每场后端面试,似乎都少不了关于 redis 的话题,比如项目使用过哪些分布式缓存服务,为什么要使用 redis,有没有碰到过缓存失效、缓存穿透、缓存雪崩等问题。
在前几篇关于 redis 的介绍文章中,我们说到项目中之所以会引入分布式缓存服务,主要是为了解决集群环境下,内存数据不共享的问题,比如 session 会话,以及一些字典缓存等等,在当前服务器的内存中存储,在另一台服务器中难以获取查询的问题,通过引入缓存服务,将缓存数据统一归一到一个服务器里面,以解决系统中内存数据不共享的问题,同时缓存性能也不会受到很大影响。
当然软件开源市场上,也有很多的分布式缓存服务,比如比较有名的有 redis、memcached 等,相对比 memcached,redis 各项指标都要比 memcached 强很多,Redis 号称能读的速度是 110000 次/s,写的速度是 81000次/s,无数的实践证明 redis 确实是当前一款非常高性能的内存数据库。
站在面试官的角度,软件系统的技术选型以及以上的相关技术问题,在实际的生产环境中确实也会发生,通过以此话题为切入点,可以更加清晰的了解面试者是否也碰到过类似的问题,以及对应处理的办法。
那么站在面试者的角度,除了熟练的掌握 redis 的使用方法以外,我们可能还需要更加深入的了解如果引入 redis 之后,系统中可能会发生的一些问题以及应对办法。
今天我们一起聊聊吧。
二、常见问题
2.1、问题一:为什么存入 redis 的数据,查询失效
Redis 的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上;也可以把每一次数据变化都写入到一个aof日志文件里面,当 redis 的服务器重启的时候,自动从日志文件里面恢复数据到内存中。
有哪些场景会发生缓存失效呢?总结起来有以下两种场景:
当 redis 服务器重启的时候,可能会发生缓存失效,此时可以将 redis 的持久化方式改成AOF模式,也就是全持久化模式,但是性能会消耗很大
存入redis 的数据,设置了自动过期时间,这种情况可以重新调整过期时间
2.2、问题二:缓存与数据库的数据不一致
通常情况下我们使用缓存,其中有一个很重要的目的就是降低数据库的访问压力,比如商品的信息查询,优先是从缓存中查询,如果没有,再从数据库里面查询。
对于既有数据库写入又有缓存操作的接口,一般分为两种情况执行。
先写入数据库,再操作缓存。这种情况下如果数据库操作成功,缓存操作失败就会导致缓存和数据库不一致
先操作缓存,再写入数据库。这种情况下如果缓存操作成功,数据库操作失败也会导致数据库和缓存不一致
大部分情况下,缓存理论上都是需要可以从数据库恢复出来的,所以基本上采取第一种顺序都是不会有问题的,但是无法保证数据库和缓存完全一致。
也就是说,使用缓存,就可能会出现缓存与数据库不一致的情况,只是说这种几几率的情况有多大。
针对那些必须保证数据库和缓存一致的情况,通常是不建议使用缓存的,直接从数据库查询。
2.3、问题三:什么是缓存穿透
缓存穿透,表示恶意用户频繁的模拟请求缓存中不存在的数据,此时如果有大量的接口请求,短时间内会直接落在了数据库上,缓存被击穿,导致数据库性能急剧下降,最终影响服务整体的性能。
这个在实际项目中很容易遇到,如抢购活动、秒杀活动、抢优惠券等接口 API 被大量的恶意用户刷,导致短时间内数据库宕机。对于缓存击穿的问题,有以下几种解决方案。
使用分布式锁排队。当从缓存中获取数据失败时,给当前接口加上锁,从数据库中加载完数据并写入后再释放锁。若其它线程获取锁失败,则等待一段时间后再重试。
使用布隆过滤器。将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力
对空结果进行缓存。如果一个查询返回的数据为空,我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟,这样第二次到缓存中获取就有值了,而不会继续访问数据库,简单粗暴好使。
2.4、问题四:什么是缓存雪崩
缓存雪崩,简单的说就是在短时间内有大量缓存失效,如果这期间有大量的请求发生,同样也有可能会导致数据库发生宕机。在 Redis 机群的数据分布算法上如果使用的是传统的 hash 取模算法,在增加或者移除 Redis 节点的时候就会出现大量的缓存临时失效的情形。
对于缓存雪崩的问题,有以下几种解决方案。
像解决缓存穿透一样加锁排队
建立备份缓存。比如缓存 A 和缓存 B,A 设置超时时间,B 不设值超时时间,先从 A 读缓存,A 没有读 B,当缓存 A 发生变化的时候,同时更新缓存 B
计算数据缓存节点的时候采用一致性 hash 算法,这样在节点数量发生改变时不会存在大量的缓存数据需要迁移的情况发生
2.5、问题五:redis 缓存会不会出现并发问题
首先 Redis 是单线程执行命令的,在出现多个 Redis Client 并发操作数据时,秉承先发起先执行的原则,其它的处于阻塞状态。
redis 缓存并发问题,其实主要指的还是读取数据库数据的并发操作问题。
当缓存过期后会从数据库查询数据然后再存入Redis缓存,但是在高并发情况下,可能还没来得及将数据库中查出来的数据存入Redis时,其它Client又从数据库里查询数据再存入Redis了。
这样一来会造成多个请求并发的从数据库获取数据,然后存入Redis,可能在读取的时候,出现脏数据。
针对这种场景,有以下几种解决方案。
同步加锁处理。在写入数据库的时候,再操作缓存这个阶段,进行加锁处理,保证服务串行,可能会牺牲一点时间
异步队列串行执行。把写入数据库和操作缓存的操作,放在队列中使其串行化,让他们一个一个的执行,比如通过消息中间件异步执行。
使用类似SQL的乐观锁机制:在并发写入Redis缓存时,把要写入数据的版本号和时间戳与Redis中的数据进行对比,如果写入的数据时间戳或者版本号 比Redis高,则写入;否则就不写入
三、小结
本文主要围绕 redis 使用中出现的一些场景问题,进行一次简单的总结,如果有疏漏的地方,欢迎网友留言指出!
四、参考
1、博客园 - 卡斯特梅的雨伞- springboot中RedisTemplate的使用
文中关于redis的知识介绍,希望对你的学习有所帮助!若是受益匪浅,那就动动鼠标收藏这篇《教你快速吃透缓存穿透、缓存雪崩及缓存击穿》文章吧,也可关注golang学习网公众号了解相关技术文章。
-
286 收藏
-
117 收藏
-
185 收藏
-
426 收藏
-
134 收藏
-
342 收藏
-
361 收藏
-
159 收藏
-
164 收藏
-
221 收藏
-
156 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习