Redis缓存危机大揭秘:雪崩、击穿与穿透——从理论到实战防御策略

        使用Redis时经常会听到缓存雪崩、缓存击穿和缓存穿透,它们到底是什么,我们应该如何应对呢?本文将向你做详细介绍。

缓存雪崩

        缓存雪崩指大量应用请求无法再Redis中进行处理,然后大量的请求就到达了数据库层,导致数据库的压力激增。缓存雪崩一般由两个原因引起:

  1. 缓存中大量数据同时过期,导致大量请求无法得到处理。
  2. Redis缓存实例发生故障宕机了,无法处理请求,这就会导致大量请求一下子积压到数据库层,从而发生缓存雪崩。

        大量数据同时过期

        当数据保存在缓存中,并且设置了过期时间,如果在某一时刻,大量数据同时过期,此时,应用在访问这些数据的话,就会发生缓存缺失。紧接着,应用就会把请求发送到数据库上,从数据库中读取数据。如果应用的并发量很大,那么数据库的压力就会很大,这会进一步影响到数据库和其他正常请求的护理。​​​​​​​

        针对大量数据同时失效带来的缓存雪崩问题,提供两种解决方案。

        首先,可以避免给大量数据设置相同的过期时间。如果业务层的确要求有些数据同时失效。可以用EXPIRE命令给每个数据设置过期时间,给这些数据的过期时间增加一个较小的随机数,这样一来,不同数据的过期时间有所差别,但差别又不大,即避免了大量数据同时过期,同时也保证了这些数据基本在相近的时间失效。

        其次可以通过服务降级来应对缓存雪崩。所谓服务降级,指不同的数据采取不通的处理方式。

  • 当业务应用访问的是非核心数据时,暂时停止从缓存中查询这些数据,而是直接返回预定义的信息。
  • 当业务应用访问的是核心数据时,仍然允许访问缓存,如果缓存缺失,继续查询数据库。

        Redis实例宕机

        Redis缓存实例发生故障宕机了,无法处理请求,这就会导致大量请求一下子积压到数据库层,从而发生缓存雪崩。

        不过在生产环境大多会才用集群部署的方式,或采用哨兵模式,总之如果主节点出现故障,能快速实现切换即可。这样可以继续提供缓存服务,避免了由于宕机而导致的缓存雪崩。

        缓存雪崩发生在大量数据同时失效的场景下,而接下来的缓存击穿,是发生在某个热点数据失效的场景下。和缓存雪崩相比,缓存击穿数据量要小的多,应对方法也不同。

缓存击穿

        缓存击穿指的是针对某个访问非常频繁的热点数据的请求,无法在缓存中进行处理,紧接着访问该数据的大量请求,一下子发到了数据库,导致数据库压力激增,会影响数据库处理其他请求。缓存击穿的情况,经常发生在热点数据过期失效时。

        为了避免缓存击穿给数据库带来激增的压力,解决方法比较直接,对于访问特别频繁的数据,我们就不设置过期时间了。这样一来,对热点数据的访问请求,都可以在缓存中进行处理,而Redis数万级别的吞吐量可以很好的应对大量的并发请求访问。

        当发生了缓存雪崩和击穿时,数据库还是保存了应用要访问的数据。缓存穿透发生时,数据不在数据库中,这是给缓存和数据库带来访问压力。

缓存穿透

        缓存穿透是指要访问的数据即不在缓存中,也不再数据库中,导致请求在访问缓存时发生缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据。此时,应用也无法从数据库中读取数据在写入缓存,来服务后续请求,这样一来缓存就成了摆设,如果此时应用有大量的请求访问数据,就会同时给缓存和数据库带来巨大压力。

        缓存穿透会在什么情况下发生呢?

  • 业务层误操作:缓存中的数据和数据库中的数据被误删除,所以缓存和数据库中都没有数据;
  • 恶意攻击:专门访问数据库中没有的数据

        为了避免缓存穿透,提供三种应对方案

        缓存空值或缺省值

        一旦发生缓存穿透,就可以针对查询的数据,在Redis中缓存一个空值或业务层约定的缺省值。紧接着应用发送的后续请求再进行查询时,就可以直接从Redis中获取空值或缺省值,返回给业务。避免把大量请求发送给数据库处理,保持数据库的正常运行。

        使用布隆过滤器

        布隆过滤器由一个初始值为0的bit数组和N个哈希函数组成,可以用来快速判断某个数据是否存在。当我们想标记某个数据存在时,布隆过滤器会通过三个操作来完成:

  1. 使用N个哈希函数,分别计算这个数据的哈希值,得到N个哈希值
  2. 把这N个哈希值对bit数组的长度取模,得到每个哈希值在数组中的对应位置
  3. 把对应bit位设置为1,这就完成了布隆过滤器中标记数据的操作

        如果数据不存在(例如数据库里没有写入数据),我们也就没有用布隆过滤器标记过数据,那么bit数组对应的bit位的值仍然是0。

        当需要查询某个数据时,就执行刚刚说的计算过程,先得到这个数据在bit数组中对应的N个位置。紧接着,我们查看bit数组中这N个位置上的bit值。只要这N个bit位上的值有一个不为1,就表明没有对该数据做过标记,所以查询的数据,一定不在数据库中。

        正是基于布隆过滤器的快速检测特性,我们可以在把数据写入数据库时,使用布隆过滤器做个标记。当缓存缺失后,应用查询数据库时,可以通过查询布隆过滤器快速判断数据是否存在。如果不存在,就不用再去数据库中查询了。这样一来,即使发生缓存穿透了,大量请求只会查询 Redis 和布隆过滤器,而不会积压到数据库,也就不会影响数据库的正常运行。布隆过滤器可以使用 Redis 实现,本身就能承担较大的并发访问压力。

        布隆过滤器存在的问题

        布隆过滤器会有误判:由于采用固定bit的数组,使用多个哈希函数映射到多个bit上,有可能会导致两个不同的值都映射到相同的一组bit上。虽然有误判,但对于业务没有影响,无非就是还存在一些穿透而已,但整体上已经过滤了大多数无效穿透请求。

        布隆过滤器误判率和空间使用的计算:误判本质是因为哈希冲突,降低误判的方法是增加哈希函数 + 扩大整个bit数组的长度,但增加哈希函数意味着影响性能,扩大数组长度意味着空间占用变大,所以使用布隆过滤器,需要在误判率和性能、空间作一个平衡,具体的误判率是有一个计算公式可以推导出来的(比较复杂)。

        布隆过滤器可以放在缓存和数据库的最前面:把Redis当作布隆过滤器时(4.0提供了布隆过滤器模块,4.0以下需要引入第三方库),当用户产生业务数据写入缓存和数据库后,同时也写入布隆过滤器,之后当用户访问自己的业务数据时,先检查布隆过滤器,如果过滤器不存在,就不需要查询缓存和数据库了,可以同时降低缓存和数据库的压力。

        Redis实现的布隆过滤器bigkey问题:Redis布隆过滤器是使用String类型实现的,存储的方式是一个bigkey,建议使用时单独部署一个实例,专门存放布隆过滤器的数据,不要和业务数据混用,否则在集群环境下,数据迁移时会导致Redis阻塞问题。

        请求入口的前端进行请求检测

        缓存穿透的一个原因是有大量的恶意请求访问不存在的数据,所以,一个有效的应对方案是在请求入口前端,对业务系统接收到的请求进行合法性检测,把恶意的请求(例如请求参数不合理、请求参数是非法值、请求字段不存在)直接过滤掉,不让它们访问后端缓存和数据库。这样一来,也就不会出现缓存穿透问题了。        

往期经典内容推荐

Redis突破性能瓶颈:揭示缓存污染之谜并采取革命性防御措施-CSDN博客

Redis 6.0进化之路:关键新特性详解_redis 6.0 特性-CSDN博客​​​​​​​

决胜高并发战场:Redis并发访问控制与实战解析-CSDN博客

  • 33
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超越不平凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值