Redis 缓存穿透问题分析与解决方案

阅读时长 5 分钟读完

缓存是提高网站性能的重要手段,而 Redis 作为一款高性能的内存数据库,被广泛应用于网站开发中。然而,伴随着缓存操作的增多,却也出现了一个被称为“缓存穿透”的难题。

所谓缓存穿透,指的是一些恶意攻击者通过构造一些不存在于数据库中的 key,频繁地向 Redis 中查询,从而造成缓存雪崩的严重后果。本文将从原理、危害及解决方案三个方面,详细分析 Redis 缓存穿透问题,并给出相应的解决方案。

Redis 缓存穿透的原理

Redis 是一款 key-value 数据库,每个 key 对应一个 value,并将数据存储在内存中,因此速度极快。因此,网站开发人员习惯于通过缓存将热点数据放在 Redis 中,以快速响应客户端请求。

而当客户端向 Redis 发起请求时,Redis 会检查请求中的 key 是否存在,如果存在则返回对应的 value,如果不存在则将请求转发到数据库中查询。然而,在缓存穿透攻击的情况下,攻击者会构造一些不存在于数据库中的 key,频繁向 Redis 发送请求,这时 Redis 会将全部请求都转发到数据库中,导致查询数据库的次数急剧增加,从而降低了网站的性能。

缓存穿透的危害

缓存穿透可能会导致以下几种危害:

  1. 浪费大量的数据库资源。
  2. 降低网站性能,导致网站响应时间加长。
  3. 由于频繁地访问数据库,可能会导致数据库崩溃,从而引发连锁反应,导致网站瘫痪。

因此,我们必须要采取有效的解决方案,避免缓存穿透问题的出现。

解决方案

方案一:布隆过滤器

布隆过滤器(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

纠错
反馈