【Redis】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 重复请求概率较高的场景而言,应该选择第一种方案。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值