Redis常见面试考点

我又来了,我是你们的IT菜菜FC,今天给大家带来的是我们在Redis中常见的面试考点,主要讲什么呢?

嗯。。。。。哦,那就今天来讲一下你对缓存穿透、缓存击穿、缓存雪崩吧。。。。

👌开始我们的表演了。。

一、缓存穿透

1. 场景介绍

我们都知道在双十一或者双十二,以及秒杀活动等等高并发的场景下,都会有很多用户购买商品,涉及到更多用户的下单情况,那么我们都会得到一个下单ID,我们可以通过这个下单ID去查询我们订单信息。但是有些坏蛋就喜欢通过一些不存在的ID来访问我们的订单信息,疯狂的发送请求来获取信息。。。。

那么我们能够想象成千上万的请求来造成我们的数据库压力。。。。

场面惨不忍睹

2. 什么是缓存穿透呢

场景介绍了这么多,那么什么缓存穿透呢?

1. 首先我们将一讲我们是怎么来做的查询(就比如订单信息)
  • 首先我们下单后会把我们的订单信息保存到数据库中,然后持久化到我们的Redis中

  • 用户通过Id来查询订单信息,首先去我们的Redis中查询数据,若有,直接返回;没有,从我们数据库中查询,在持久化到Redis中
    我们通常的操作就是这样的

2. 概念

其实缓存缓存穿透的概念很简单,有些坏蛋喜欢通过一些不合法以及不存在的ID来疯狂访问我们的API,首先先从我们的redis中去查询,若没有,就去数据库中查询,结果也没有,这样造成我们数据库压力很大,这就出现了缓存穿透

3. 解决办法

1. 缓存空对象

首先我们从我们的Redis中查询数据,没有命中,再去我们的数据库中查询,也没有命中,那么我们可以将其设置为null,保存redis缓存中,当用户在此访问这个Id查询时,直接返回给用户null或者没有数据或稍后再试的信息反馈,同时会设置过期时间,用户在此访问就会从数据库中查询,这样来保护我们的后端资源。

​ 这样方法有没有什么缺点呢?

缓存空对象听着好像可以哈。。。。但是。。。。嘿嘿😁

  1. 如果这样的话,我们就需要缓存很多这样的键,这样我们缓存中就会有很多null的键,浪费了很大的空间资源

  2. 即使对空值设置了过期时间,还会存在缓存层和储存层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响

2. 使用布隆过滤器(推荐使用这种方法)

利用高效的数据结构和算法快速判断出你这个key是否存在数据库中,不存在直接return,存在就去查询DB刷新KV再return

二、 缓存雪崩

1.场景介绍

​ 在我们的电商项目中我们都会将首页的数据放入到我们的Redis中缓存起来,设置过期时间,用户直访问我们的数据从Redis中获取

2. 什么是缓存雪崩呢

1. 基本操作

在我们电商项目中,我们都会把这些首页数据放入到我们的缓存中去,设置过期时间,用户来访问数据,直接从Redis中获取信息,返回给用户

2. 概念:

举个例子:如果我们的首页Key失效时间都是设置的在12小时,那么在中午12点刷新,在凌晨的时候有个秒杀活动大量用户涌入,假设当时每秒6000个请求,本地缓存可以扛住每秒5000个请求,但是在那时缓存失效了,此时的请求全部打到了数据库上面,那么数据库肯定抵不住的。

同一时间大面积失效,那一瞬间Redis跟没有一样,那么这个请求直接打到数据库上面是灾难性的,你想想如果打挂的是一个用户服务的库,那其他依赖他的库所有的接口几乎都会报错,如果没做熔断等策略基本上就是瞬间挂一片的节奏,你怎么重启用户都会把你打挂,等你能重启的时候,用户早就睡觉去了,并且对你的产品失去了信心,什么垃圾产品。

3. 解决办法
  1. 在批量往Redis存数据的时候,我们吧每个Key的过期时间设置为随机值,这样可以保证数据在同一时间不会大面积失效

    setRedis(Key,value,time + Math.Random() * 1000)

    如果Redis是集群部署,将热点数据均匀分布在不同的Redis库中也能避免全部失效的问题,不过本渣我在生产环境中操作集群的时候,单个服务都是对应的单个Redis分片,是为了方便数据的管理,但是也同样有了可能会失效这样的弊端,失效时间随机是个好策略。

  2. 设置热点数据永远不过期,有更新操作直接更新缓存,这样做比较保险

三、缓存击穿

1. 场景介绍

在我们的电商项目中我们都会将热点数据放入到我们的Redis中缓存起来,设置过期时间,用户直访问我们的数据从Redis中获取

2. 什么是缓存击穿呢

1. 基本操作

在我们电商项目中,我们都会把这些首页数据放入到我们的缓存中去,设置过期时间,用户来访问数据,直接从Redis中获取信息,返回给用户

2. 概念:

跟缓存雪崩有点像,但有不一样,缓存雪崩是因为大面试缓存失效,请求直接打到数据库中。而缓存击穿不同的是指一个热点数据Key在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个完好无损的桶上凿开了一个洞。

3. 解决办法
  1. 可以设置热点数据永不过期
  2. 加上互斥锁
public static String getData(Sting key)throws InterruptedException{

// 从redis中获取数据
String result = getDataRedis(Key);

// 数据校验
if(StringUtils.isBlank(result)){

// 获取锁
if(reenLock.tryLock()){
// 去数据库中查询数据
result = getDataDB(key);

// 数据校验
if(StringUtils.isNotBlank(result)){

// 刷新缓存
setDataRedis(key, result);
}
// 释放锁
reenLock.unlock();
}else{

// 休眠
Threed.sleep(100L);

result = getDataByRedis(Key);
}
}
return result;
}