Redis缓存常见问题——穿透、击穿、雪崩

Redis缓存常见问题——穿透、击穿、雪崩

Redis最常用来做缓存,它是基于内存来操作数据的,当数据量过大时难免会遇到一些缓存问题。这篇文章就来说一说Redis常见的缓存问题。

缓存穿透

我们说当发送请求来查询某个数据时,首先会从Redis缓存中查询,如果缓存中有就直接返回,如果没有请求才会到数据库中查询。而缓存穿透指的就是当访问一个redis缓存和数据库都不存在的key时,此时这个请求就会直接到数据库中查询,但是数据库中也查不到任何数据,而且也没有办法写缓存。这样情况缓存相当于没起作用,当请求量过大时,数据库很有可能会挂掉。

Redis缓存本来想起到一个“半路拦截”的作用,替数据库缓解一下压力,缓存穿透的发生,请求就当Redis缓存不存在,直接穿过了Redis缓存,缓存相当于拦了个寂寞,还是得有数据库来处理请求。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LrMDfMj7-1632379362761)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210923132925914.png)]

对于缓存穿透的问题,我们该如何解决?

  1. 接口校验

    在调用接口时,可以在最外层先做一层校验,比如用户鉴权、数据合法性校验等等,提前过滤掉一些非法的接口请求。例如商品查询中,商品的ID是正整数,则可以直接对非正整数ID的请求直接过滤掉。

  2. 缓存空值

    当访问缓存和数据库都没有的数据时,可以将一个空值写入缓存,并给这个空值设置较短的过期时间,防止这个无效值一直占有内存。

  3. 布隆过滤器

    可以使用布隆过滤器存储所有可能访问的key,当用户请求过来,先判断用户发来的请求的key是否存在于布隆过滤器中,不存在的key直接被过滤掉,存在的key则进一步查询缓存和数据库。布隆过滤器相当于在Redis缓存前面又进行了一次拦截校验。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wujVdlFx-1632379362770)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210923134318939.png)]

布隆过滤器特别使用在海量数据中进行查询,那它的实现原理到底是什么?实际上布隆过滤器在Redis中的数据结构就是一个大型的位数组+多个随机映射的哈希函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OzYWiLtg-1632379362781)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210824100412644.png)]

向布隆过滤器中添加key时,会使用多个hash函数计算这个key的hash值,并转换为数组中对应的索引值,然后对数组长度进行取模运算得到具体的存放位置,每一个hash函数都会计算出不同的位置,然后把数组中对应的位置置为1,就相当于完成添加操作。

当一个请求向布隆过滤器查询一个key是否存在时,跟添加操作一样,会把这个要查询的key通过hash函数计算出数组中对应的索引位置,看看数组中这个位置是否都为1,只要有一个位置为0,则说明布隆过滤器中不存在这个key。如果这几个位置都为1,并不能说明这个key一定存在,只是有非常大概率存在,因为这些位置为1很有可能是因为其它key存在所导致的。如果这个数组比较稀疏,那么布隆过滤器判断正确的概率还是很大的,如果说这个位数组比较密集,那么判断正确的概率就会降低。

布隆过滤器空间占用的大小,可能会影响到判断元素是否存在的精准度。

布隆过滤器有两个参数:

  • 第一个参数是预计元素的数量n
  • 第二个参数是错误率f

布隆过滤器的空间占用计算公式根据这两个参数输入得到两个输出:

  • 第一个输出是数组的长度l,也就是需要的存储空间大小(bit)
  • 第二个输出是**hash函数的最佳数量k。**hash函数的数量也会直接影响到错误率,最佳的数量会有最低的错误率。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-36ORQjrK-1632379362783)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210824102156782.png)]

当实际元素超出预计元素时,错误率会上升

布隆过滤器可以过滤查询redis缓存的请求,防止redis发生缓存穿透。

缓存击穿

某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库。

要区分开缓存穿透和缓存击穿,穿透更像是一把散弹枪,大量的请求瞄准不同的key进行“射击”。而击穿,更像是一把AK47冲着墙上一个点进行连续射击,缓存过期的那一瞬间,相当于墙上被打出一个洞,直接击穿了Redis这面墙,大量请求查询同一个key。

对于缓存击穿该如何解决?

  1. 加互斥锁

    在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,其它请求直接走缓存查询数据。

  2. 热点数据设置不过期

    直接将缓存设置为不过期,然后由定时任务去异步加载数据,更新缓存。这种方式适用于比较极端的场景,例如流量特别特别大的场景。很有可能发生异常,缓存无法更新

缓存雪崩

大量的热点 key 设置了相同的过期时间,导致缓存在同一时刻全部失效,造成瞬时数据库请求量大、压力骤增,引起雪崩,甚至导致数据库被打挂。缓存雪崩其实有点像“升级版的缓存击穿”,缓存击穿是一个热点 key,缓存雪崩是一组热点 key。

对于缓存雪崩该如何解决?

  1. 分散过期时间

    可以给缓存的过期时间时加上一个随机值时间,使得每个 key 的过期时间分布开来,不会集中在同一时刻失效。

  2. 热点数据不过期

    该方式和缓存击穿一样,也是要着重考虑刷新的时间间隔和数据异常如何处理的情况。

  3. 加互斥锁

    该方式和缓存击穿一样,按 key 维度加锁,对于同一个 key,只允许一个线程去计算,其他线程原地阻塞等待第一个线程的计算结果,然后直接走缓存即可。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值