【Redis】Redis 高并发处理策略

在现实中很多的业务场景里,人们常常使用 Redis 作为缓存使用。其性能高,支持数据结构丰富,还具备多种优势特性。

在日常业务中,通常的请求处理过程为:业务系统有请求进来,先查缓存,查不到数据再去查 DB 层,命中后回写缓存,再返回数据。这种模式称之为“赖加载”模式。这样使用缓存策略一般也不会遇到问题,但是当业务平台越来越大,用户数量越来越大的时候。平台要开始考虑高并发场景下是否系统是否支撑的下去。尤其是考虑瞬间大量请求时,系统如何设计。

在这里插入图片描述

存在读写压力,可以采用数据库分库分表的方式,不过基于成本考虑,数据库节点不能无限增加。而且在高并发场景下,数据库的读写速度还是不够快,不足以支撑追求更高吞吐量和更快响应速度。因此,考虑到 Redis 的高性能特性,这时就要考虑下采用怎样的缓存处理策略了。

1、数据预热(避免懒加载)

假设这么一个场景:双十一当天刚刚过 0 点的瞬间,有大量的下单请求到达,如果这时我们采用传统的”懒加载“缓存模式,那么这些大量的请求,将会瞬间全部请求到 DB 层,服务系统就直接宕机了。此时缓存没有来得及产生任何作用,在当前服务挂了以后,还有可能会影响到其他关联服务,从而导致服务雪崩。

针对上述场景的一个解决方案是采用数据预热的方式。在可预见的大量请求到来之前,我们可以通过手动或者定时任务的方式,将相关的数据批量写入到 Redis 缓存中,这样就可以避免大量的基础数据请求直接打到数据库上,从而减轻数据库的读写压力,间接保护了数据库。

2、散列开缓存过期时间(避免缓存雪崩)

缓存雪崩的概念是:Redis 中缓存数据的过期时间过于集中,到达某个时间后,大量缓存集中失效。在缓存大量失效且出现高并发的场景下,大量请求就会击穿缓存,直接打到数据库上。

一种处理方案是,将过期时间散列开来,具体可以通过设置一个过期时间基数,再加上一个随机数作为偏移值。这样就可以避免由于缓存过期时间而导致的缓存集中失效,从而避免出现缓存雪崩问题。

实际上,如果不能将缓存过期时间散列开的话,另一个解决方式是通过定时任务的方式,在缓存过期之前重新批量获取最新的数据,并将其更新到缓存中,重置缓存时间。这样子就能保证缓存关键字会一直存在,不会发生缓存雪崩的现象。

3、分布式锁

通过上面的方法,可以避免大量缓存失效的情况。但是,当某个缓存关键字过期之后,缓存数据还是要失效。此时,在高并发场景下,大量请求还是会直接打到数据库上。这时可以采用分布式锁来控制缓存重建的过程,以保护数据库。

在这里插入图片描述

该方案的实现原理为,当发现某一个热点数据失效后,启用分布式锁。此时如果有大量请求访问应用系统,那么我们只允许一个线程加锁成功,允许其访问数据库重建缓存,其他线程须等待缓存重建后,重新从缓存获取数据, 从而保护数据库。

4、散列开数据

如果某个数据实在是太热门了,海量请求不断来袭,此时单个 Redis 节点可能无法支撑那么高的负载。那么就可以采用将数据散列开的方案。

具体操作为:将热点数据的 key 做成多份,均匀散列到多个 Redis 集群中,这样数据请求能均匀打散到这些 Redis 节点上,分担了读压力,缓解了缓存的负载。

5、防御缓存穿透

我们在上面已经有描述过缓存穿透的场景。当我们的业务系统受到大量恶意请求,或者受到黑客攻击,去查询那些既不存在于缓存,也不存在于数据库里的数据,此时缓存就失去了保护数据库的作用。要应对这种情况,通常可以采用缓存空数据或者采用布隆过滤器(BloomFilter)。

缓存空数据

顾名思义,将数据库查询结果为空的 key 也存储在缓存中。当后续出现对该 key 的查询请求时,缓存直接返回空值 null,而避免了其访问数据库。

在这里插入图片描述

不过,缓存空对象也会存在一些弊端:

  • 空值 null 做了缓存,那就意味着缓存中存储了更多的 key,而这些 key 本身会占用更多的内存空间。
  • 缓存与数据库的数据可能会在一段时间内存在数据不一致的情况,这可能会影响到业务。例如,原来在缓存中存有空值的关键字,在数据库里得到更新,获得了非空的值,但这个数据并没有及时同步到缓存中,那么就会影响到相关的业务。

针对上述问题,如果确定 key 对应的数据不会出现有效数据,那么可以针对这类 key 设置一个较短的过期时间,让其自动删除,以释放内存。至于数据一致性问题,可以通过各种策略数据库更新后的数据及时同步到缓存中,最直接的方式就是,每次数据库数据更新,马上对这个 key 的缓存执行一次同步操作。

BloomFilter

布隆过滤器的基本原理是,一个比特位就可以标识一个数据,因此可以节省大量的空间,具体的算法原来在这里就不赘述了。在 Redis 4.0 后,布隆过滤器已经作为一个插件加载到 Redis Server 中了。

在这里插入图片描述

查询请求过来时,首先会去布隆过滤器中查询该 key 是否存在,如果不存在,说明数据库也不会存在该数据,因此缓存也不需要查询了,直接返回空结果。如果存在,则继续按照正常流程执行,先查询缓存,缓存中没有数据时再去查询数据库。

缓存空数据 VS BloomFilter

对于一些恶意攻击,查询的 key 往往各不相同,而且数据数量特别多。此时,第一种方案就显得劣势很大了。因为它需要存储所有空数据的 key,而这些恶意攻击的 key 往往各不相同,不容易预测,而且同一个 key 往往只请求一次。因此即使缓存了这些空数据的 key,由于不再使用第二次,因此也起不了保护数据库的作用。

因此,对于空数据的 key 各不相同、key 重复请求概率低的场景而言,应该选择第二种方案。而对于空数据的 key 数量有限、key 重复请求概率较高的场景而言,应该选择第一种方案。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值