Redis相关面试题

一 : 缓存雪崩

1.1 定义

缓存雪崩是指在短时间内,有大量缓存同时过期,导致大量的请求直接查询数据库,从而对数据库造成了巨大的压力,严重情况下可能会导致数据库宕机 .

我们来看下正常情况下和缓存雪崩时程序的执行流程图,正常情况下系统的执行流程如下图所示 :

在这里插入图片描述

缓存雪崩时程序的执行流程图如下图所示 :

在这里插入图片描述

简图 :
在这里插入图片描述

那么如何解决缓存雪崩的问题呢 ?

1.2解决方案

1.2.1 加锁排队

加锁排队可以起到缓冲的作用,防止大量的请求同时操作数据库,但它的缺点是增加了系统的响应时间,降低了系统的吞吐量,牺牲了一部分用户体验 .

1.2.2 随机化过期时间

随机化过期时间 . 为了避免缓存同时过期,可在设置缓存时添加随机时间,这样就可以极大的避免大量的缓存同时失效 .

//缓存原本的失效时间
int exTime = 10*60
Random random = new Random();
//缓存设置
jedis.setex(cacheKey,exTime+random.nextInt(1000),value);

1.2.3 设置二级缓存

二级缓存指的是除了 Redis 本身的缓存,再设置一层缓存,当 Redis 失效之后,先去查询二级缓存 .

加入二级缓存之后的程序执行流程 :

在这里插入图片描述

二 : 缓存穿透

2.1 定义

缓存穿透是指查询数据库和缓存都无数据,因为数据库查询无数据,出于容错考虑,不会将结果保存到缓存中,因此每次请求都会去查询数据库,这种情况就叫做缓存穿透 .

缓存穿透执行流程如下图所示 :

在这里插入图片描述

红色路线就是缓存穿透的结果 . 缓存根本没起到作用 , 好像被穿透了一样,每次都会去访问数据库 .

如何解决缓存穿透问题呢 ? 本质上就是要防止用户查不到数据 ! 有以下几种方案 .

2.2 解决方案

2.2.1 校验参数

我们可以对用户id做检验。

比如你的合法id是15xxxxxx,以15开头的。如果用户传入了16开头的id,比如:16232323,则参数校验失败,直接把相关请求拦截掉。这样可以过滤掉一部分恶意伪造的用户id。

2.2.2 布隆过滤器

如果数据比较少,我们可以把数据库中的数据,全部放到内存的一个map中。

这样能够非常快速的识别,数据在缓存中是否存在。如果存在,则让其访问缓存。如果不存在,则直接拒绝该请求。

但如果数据量太多了,有数千万或者上亿的数据,全都放到内存中,很显然会占用太多的内存空间。

那么,有没有办法减少内存空间呢?

答:这就需要使用布隆过滤器了。

布隆过滤器底层使用bit数组存储数据,该数组中的元素默认值是0 .

布隆过滤器第一次初始化的时候,会把数据库中所有已存在的key,经过一系列的hash算法(比如:三次hash算法)计算,每个key都会计算出多个位置,然后把这些位置上的元素值设置成1。

在这里插入图片描述
之后,有用户key请求过来的时候,再用相同的hash算法计算位置。

如果多个位置中的元素值都是1,则说明该key在数据库中已存在。这时允许继续往后面操作。

如果有1个以上的位置上的元素值是0,则说明该key在数据库中不存在。这时可以拒绝该请求,而直接返回。

使用布隆过滤器确实可以解决缓存穿透问题,但同时也带来了两个问题:

  1. 存在误判的情况。

  2. 存在数据更新问题。

先看看为什么会存在误判呢?

上面我已经说过,初始化数据时,针对每个key都是通过多次hash算法,计算出一些位置,然后把这些位置上的元素值设置成1。

但我们都知道hash算法是会出现hash冲突的,也就是说不同的key,可能会计算出相同的位置。
在这里插入图片描述

上图中的下标为2的位置就出现了hash冲突,key1和key2计算出了一个相同的位置。

如果有几千万或者上亿的数据,布隆过滤器中的hash冲突会非常明显。

如果某个用户key,经过多次hash计算出的位置,其元素值,恰好都被其他的key初始化成了1。此时,就出现了误判,原本这个key在数据库中是不存在的,但布隆过滤器确认为存在。

如果布隆过滤器判断出某个key存在,可能出现误判。如果判断某个key不存在,则它在数据库中一定不存在。

通常情况下,布隆过滤器的误判率还是比较少的。即使有少部分误判的请求,直接访问了数据库,但如果访问量并不大,对数据库影响也不大。

此外,如果想减少误判率,可以适当增加hash函数,图中用的3次hash,可以增加到5次。

其实,布隆过滤器最致命的问题是:如果数据库中的数据更新了,需要同步更新布隆过滤器。但它跟数据库是两个数据源,就可能存在数据不一致的情况。

比如:数据库中新增了一个用户,该用户数据需要实时同步到布隆过滤。但由于网络异常,同步失败了。

在这里插入图片描述

这时刚好该用户请求过来了,由于布隆过滤器没有该key的数据,所以直接拒绝了该请求。但这个是正常的用户,也被拦截了。

很显然,如果出现了这种正常用户被拦截了情况,有些业务是无法容忍的。所以,布隆过滤器要看实际业务场景再决定是否使用,它帮我们解决了缓存穿透问题,但同时了带来了新的问题。

2.2.3 缓存空值

上面使用布隆过滤器,虽说可以过滤掉很多不存在的用户id请求。但它除了增加系统的复杂度之外,会带来两个问题:

布隆过滤器存在误杀的情况,可能会把少部分正常用户的请求也过滤了。

如果用户信息有变化,需要实时同步到布隆过滤器,不然会有问题。

所以,通常情况下,我们很少用布隆过滤器解决缓存穿透问题。其实,还有另外一种更简单的方案,即:缓存空值。

当某个用户id在缓存中查不到,在数据库中也查不到时,也需要将该用户id缓存起来,只不过值是空的。这样后面的请求,再拿相同的用户id发起请求时,就能从缓存中获取空数据,直接返回了,而无需再去查一次数据库。

优化之后的流程图如下:

在这里插入图片描述

关键点是不管从数据库有没有查到数据,都将结果放入缓存中,只是如果没有查到数据,缓存中的值是空的罢了 .

三 : 缓存击穿

3.1 定义

缓存击穿指的是某个热点缓存,在某一时刻恰好失效了,然后此时刚好有大量的并发请求,此时这些请求将会给数据库造成巨大的压力,这种情况就叫做缓存击穿。

比如双十一到了 , 我们在淘宝购买"背带裤" , 通常情况下,商城系统会把"背带裤"信息放到缓存中。但如果某个时刻,该商品到了过期时间失效了。

此时,如果有大量的用户请求"背带裤",但该商品在缓存中失效了,一下子这些用户请求都直接怼到数据库,可能会造成瞬间数据库压力过大,而直接挂掉。

在这里插入图片描述

其执行流程简图为 :

在这里插入图片描述

它的解决方案有以下 2 个。

3.2 解决方案

3.2.1 加锁排队

此处理方式和缓存雪崩加锁排队的方法类似,都是在查询数据库时加锁排队,缓冲操作请求以此来减少服务器的运行压力。

3.2.2 自动续期

出现缓存击穿问题是由于key过期了导致的。那么,我们换一种思路,在key快要过期之前,就自动给它续期,不就OK了?

答:没错,我们可以用job给指定key自动续期。

比如说,我们有个分类功能,设置的缓存过期时间是30分钟。但有个job每隔20分钟执行一次,自动更新缓存,重新设置过期时间为30分钟。

在这里插入图片描述

这样就能保证,分类缓存不会失效。

此外,在很多请求第三方平台接口时,我们往往需要先调用一个获取token的接口,然后用这个token作为参数,请求真正的业务接口。一般获取到的token是有有效期的,比如24小时之后失效。

如果我们每次请求对方的业务接口,都要先调用一次获取token接口,显然比较麻烦,而且性能不太好。

这时候,我们可以把第一次获取到的token缓存起来,请求对方业务接口时从缓存中获取token。

同时,有一个job每隔一段时间,比如每隔12个小时请求一次获取token接口,不停刷新token,重新设置token的过期时间。

3.2.3 设置永不过期

对于某些热点缓存,我们可以设置永不过期,这样就能保证缓存的稳定性,但需要注意在数据更改之后,要及时更新此热点缓存,不然就会造成查询结果的误差。

参考文章 : 缓存穿透,缓存击穿,缓存雪崩详解及解决办法[通俗易懂]

四 : 缓存预热

4.1 定义

首先来说,缓存预热并不是一个问题,而是使用缓存时的一个优化方案,它可以提高前台用户的使用体验。缓存预热指的是在系统启动的时候,先把查询结果预存到缓存中,以便用户后面查询时可以直接从缓存中读取,以节约用户的等待时间。

缓存预热的执行流程,如下图所示:

在这里插入图片描述
缓存预热的实现思路有以下三种 .

4.2 实现思路

  1. 把需要缓存的方法写在系统初始化的方法中,这样系统在启动的时候就会自动的加载数据并缓存数据;
  2. 把需要缓存的方法挂载到某个页面或后端接口上,手动触发缓存预热;
  3. 设置定时任务,定时自动进行缓存预热。

本文到此结束 !

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值