Redis的三大常见问题
如果是一名能够熟练的将Redis运用到项目中的程序员,那么一定听说过Redis在使用中存在的问题,那么我们今天就来聊聊Redis的三大问题
为什么会有三大问题?
首先,对于很多刚接触Redis的同学,很多时候分不清Redis的作用,不太理解为什么要在SQL之外单独在搞一个Redis出来。
首先,只要接触过Redis,那么你一定知道Redis是用来作为缓存的,但是这只是一句空话,什么叫缓存?为什么要缓存?
什么叫缓存?
通俗的说,缓存就是把部分数据拿出来,然后放到一个地方(缓存区)。别人在查找数据的时候,先去看缓存里有没有数据,如果有,则从缓存区中直接拿,否之再查询数据库。
为什么要缓存
缓存自然有缓存的好处。
众所周知,Redis的数据是存放到内存上的,而Mysql的数据大多数情况是存放在硬盘上的,而总所又周知,内存的存取速度是高于硬盘的,因此缓存就可以提高一次查询的查询速度。
同时,由于Redis的并发处理能力高于Mysql,因此查询数据通过先查询Redis再查询Mysql的形式也能减小Mysql的压力。
除此之外,Redis也经常负责一些不适合/没必要存到Mysql中的数据(比如一些会经常删改的数据,内容较短且较少的数据,或者需要定时过期的数据)
缓存雪崩
场景
在Redis中,我们有时会给一个数据设计一个存储时间,假设在某一时刻,大量的数据同时过期,,而这时因为我们应用的一个高并发,因此导致大量请求直接跨过Redis直达Mysql,这就导致了Mysql的压力过大,甚至可能会导致Mysql的崩溃。
解决方案
自然就是对一些会长期使用的数据不设置过期时间,但同样的这也会导致内存数据的推挤,不过这个问题可以靠升级服务器(money)解决。
缓存穿透
场景
假设有人恶意攻击我们的服务器,那么它可以通过查询一个肯定不存在的数据来造成一个超高的并发量,由于数据不存在,这个数据自然会直接打到Mysql上,进而对Mysql造成极大压力
解决方案
-
一旦发现一个空值,就像Redis中添加一个数据,这样就避免了大量的恶意请求,但是与缓存雪崩不同,这个数据的量是无法估计的(恶意请求无限多),因此我们还需要单独设置一个过期时间
-
引入布隆过滤器
布隆过滤器是一种数据结构,用于判断一个数据是否在一个集合当中,布隆过滤器的判断方式保证了若给出结果为不存在则一定正确(不可能有认为不存在的数据存在),若给出结果为存在则不一定正确(可能有一些认为存在的数据不存在)
在这种情况下,我们先把Mysql中数放存到布隆过滤器中,顺序变为布隆过滤器——>Redis——>Mysql。
接着我们来看布隆过滤器的处理方案
若判断为不存在:直接相应请求,且判断一定正确。
若存在:查询Redis缓存,若没有则查询数据库(注意,由于布隆过滤器不能判定存在可能出错的原因,这里的数据可能是不存在),然后再放到Redis中,再返回数据。
这里可能已经有小伙伴发现,布隆过滤器解决存在的方案就是1的方案,但是由于有了布隆过滤器的存在,可以进一步减小压力与内存的浪费
缓存击穿
场景
缓存击穿的场景类似于缓存雪崩。
缓存击穿是大量请求请求一个数据,而这一个数据过期。(多*1=多)
缓存雪崩是一些请求(可能不算很多)请求大量数据,而这些数据集体过期(少*少=多)
因此缓存击穿设计的数据往往是热点数据(只有热点数据才会高额请求一个数据)
解决方案
-
不设置过期时间解决一切问题
-
添加分布式锁
涉及技术:Lua脚本再Redis中的使用
对Redis的数据加锁(通过再Redis中使用Lua脚本实现锁功能),保证当缓存失效时只有一个服务实例去数据库中获取数据并更新缓存,进而避免了大量数据进入Mysql。
-
引入本地缓存与Redis互补(通俗的说就是再加一层缓存)
涉及技术:本地缓存(可以使用Google开源的Caffeine)
顺序:本地缓存——>Redis——>Mysql
将本地缓存的时间设置为与Redis不同
- 都未过期:直接返回
- 本地缓存过期Redis未过期:直接从Redis取,放到本地缓存,再返回
- Redis过期,本地缓存未过期:直接返回
- 都过期:访问Mysql,再放到Redis,再放到本地缓存
通过这种模式减小了击穿的概率,还可以通过再步骤3将本地缓存同步到Redis,以及涉及多个本地缓存的方式进一步优化减小压力
-
热点 Key 探测,延长缓存失效时间
这种方案是实时判断Redis中哪些中哪些数据是热点数据,再对这些数据进行及时的续签。
该方案技术难度较大,这里给大家推荐一篇大厂的文章得物技术团队——热点探测技术架构设计与实践