缓存是提高网站性能的重要手段,而 Redis 作为一款高性能的内存数据库,被广泛应用于网站开发中。然而,伴随着缓存操作的增多,却也出现了一个被称为“缓存穿透”的难题。
所谓缓存穿透,指的是一些恶意攻击者通过构造一些不存在于数据库中的 key,频繁地向 Redis 中查询,从而造成缓存雪崩的严重后果。本文将从原理、危害及解决方案三个方面,详细分析 Redis 缓存穿透问题,并给出相应的解决方案。
Redis 缓存穿透的原理
Redis 是一款 key-value 数据库,每个 key 对应一个 value,并将数据存储在内存中,因此速度极快。因此,网站开发人员习惯于通过缓存将热点数据放在 Redis 中,以快速响应客户端请求。
而当客户端向 Redis 发起请求时,Redis 会检查请求中的 key 是否存在,如果存在则返回对应的 value,如果不存在则将请求转发到数据库中查询。然而,在缓存穿透攻击的情况下,攻击者会构造一些不存在于数据库中的 key,频繁向 Redis 发送请求,这时 Redis 会将全部请求都转发到数据库中,导致查询数据库的次数急剧增加,从而降低了网站的性能。
缓存穿透的危害
缓存穿透可能会导致以下几种危害:
- 浪费大量的数据库资源。
- 降低网站性能,导致网站响应时间加长。
- 由于频繁地访问数据库,可能会导致数据库崩溃,从而引发连锁反应,导致网站瘫痪。
因此,我们必须要采取有效的解决方案,避免缓存穿透问题的出现。
解决方案
方案一:布隆过滤器
布隆过滤器(Bloom Filter)是一种快速且占用空间较小的数据结构,常用于判断一个元素是否在集合中。布隆过滤器中存储了一些 hash 函数,通过这些 hash 函数将元素映射到一个二进制向量中,并将相应位置标记为 1。当一个元素进入布隆过滤器中时,它的每个 hash 值被映射到二进制向量上,将相应的位置标记为 1。在查询元素是否在集合中时,将元素的 hash 值映射到二进制向量上,查看相应的位置是否都为 1,如果都为 1,则说明该元素可能存在于集合中。
在使用布隆过滤器时,我们需要在 Redis 中建立一个布隆过滤器,每当一个请求到达时,先将该请求的 key 传入布隆过滤器中验证,如果不存在则说明该 key 不存在于 Redis 中,直接返回 null 值即可。
示例代码如下:
-- -------------------- ---- ------- ----- ----- - ----------------- ----- ----------- - ------------------------ ----- ------ - --------------------- ----- ------ - --- ---------------- - ----- --- --- ----- -------- --------------------- - -- ------------------ - ------ ----- - ------ ----- --------------------- - ----- -------- -------------- ------ - ----- -------------------- ------- ---------------- -
方案二:缓存空对象
由于 Redis 中不存在的 key 返回 null 值,因此我们可以在 Redis 中存储一个空对象,表示此 key 查询过但查询结果为空。
示例代码如下:
-- -------------------- ---- ------- ----- ----- - ----------------- ----- ------ - --------------------- ----- -------- --------------------- - ----- ---- - ----- --------------------- -- ----- --- ----- - ------ ----- - -- ----- --- ----- - ------ --- - ------ ----------------- - ----- -------- -------------- ------ - -- ------ --- ----- - ----- -------------------- ------ - ---- - ----- -------------------- ----------------------- - -
方案三:缓存过期时间
我们可以为 Redis 中的每个 key 设置一个过期时间,当一个不存在于数据库中的 key 被查询时,Redis 会将其缓存一段时间(一般为几分钟),过了有效期之后再查询数据库中是否存在。
示例代码如下:
-- -------------------- ---- ------- ----- ----- - ----------------- ----- ------ - --------------------- ----- -------- --------------------- - ----- ---- - ----- --------------------- -- ----- --- ----- - ------ ----- - -- ----- --- ----- - ------ --- - ------ ----------------- - ----- -------- -------------- ------ - -- ------ --- ----- - ----- ---------------------- ---- ------ - ---- - ----- ---------------------- ---- ----------------------- - -
总结
缓存穿透是一个非常棘手的问题,我们需要通过布隆过滤器、缓存空对象、缓存过期时间等多种方式来避免缓存穿透问题的发生。然而,我们也不能一开始就将信誉度掏空,而是需要通过黑名单、IP 屏蔽等方式来避免恶意攻击者的入侵,从而保证网站的正常运行。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64aa305348841e989465b5af