redis 缓存带来的问题及优化方案

阅读时长 10 分钟读完

随着前端技术的普及和前后端分离的盛行,前端对缓存的需求也越来越高。利用 Redis 缓存可以显著提高网站的性能,降低服务器负荷,但是也需要注意它所带来的一些问题,以及如何做出优化。

问题

缓存雪崩

缓存雪崩是指在 Redis 缓存中,由于缓存键的过期时间相同或接近,导致缓存同时失效,请求都落在了数据库上,造成数据库短时间内瞬时并发访问压力太大,从而导致数据库宕机的现象。

-- -------------------- ---- -------
-- ----
-- ------------
----------------- - ----- ------ ---- -- -- ----- ------

-- ---- ---- --
----- -------- --------- -
  --- ---- - ----- ------------------
  -- ------- -
    -- -----------
    ---- - ----- ----------------
    -- ----
    ----------------- ----- ----- ------
  -
  ------ -----
-
展开代码

以上示例代码中,由于缓存过期时间一致,如果同时失效,则在从数据库获取数据时会同时发起大量请求,导致数据库可能会宕机,从而引发缓存雪崩。

缓存穿透

缓存穿透是指在 Redis 缓存中,由于恶意攻击或者业务逻辑bug,在缓存和数据库中均不存在某个键,这时大量请求都会落在数据库上,造成数据库短时间内瞬时并发访问压力太大,从而导致数据库宕机的现象。

-- -------------------- ---- -------
-- ----
-- ------
----- -------- --------------- -
  --- ---- - ----- ----------------- - ----
  -- ------- -
    ---- - ----- ----------------------
    -- ------- -
      -- -----
      ----------------- - --- --- ----- ------
      ------ -----
    -
    ----------------- - --- ----- ----- ------
  -
  ------ -----
-
展开代码

为了防止缓存穿透,通常会在 Redis 缓存中把不存在的键写入一个空值,这样下次请求过来时就只会落在 Redis 缓存中。但是如果攻击者频繁的请求数量太大,仍然会对数据库造成压力。

缓存击穿

缓存击穿是指在 Redis 缓存中,由于一个热点数据缓存过期或者业务逻辑高频访问,而导致这个键的大量请求都会落在数据库上,造成数据库短时间内瞬时并发访问压力太大,从而导致数据库宕机的现象。

-- -------------------- ---- -------
-- ----
-- ------
----- -------- --------------- -
  --- ---- - ----- ----------------- - ----
  -- ------- -
    -- ------------------------------
    -- ------ ----------------------- - --- ---- ----- ----- ---- -
      ---- - ----- ----------------------
      -- ------- -
        -- -----
        ----------------- - --- --- ----- ------
        ------ -----
      -
      ----------------- - --- ----- ----- ------
      -- ---
      ----------------------- - ----
    - ---- -
      -- ---------------------------------------
      ----- ---------
      ------ ----- ----------------
    -
  -
  ------ -----
-
展开代码

为了防止缓存击穿,通常会在 Redis 缓存中加入互斥锁。当一个请求到来时,如果获取到了锁,那么它就可以从数据库中获取数据,然后写入缓存,并释放锁。如果一个请求到来时没有获取到锁,则等待一段时间(比如50ms),再次尝试获取缓存即可。

优化方案

缓存雪崩优化

为了避免缓存雪崩的发生,可以采取以下几种优化方案:

  1. 不同缓存键设置不同的过期时间,避免同时失效;
  2. 缓存失效时不是立即从数据库中获取数据,在某个随机的时间点再去获取数据;
  3. 对于实时性要求不高的数据,可以在高峰期对其进行预热,提前将其写入缓存中。
-- -------------------- ---- -------
-- ----
-- --------------
---------------------- - ----- ------ ---- -- -- ----- ------
---------------------- - ----- -------- ---- -- -- ----- ------
---------------------- - ----- -------- ---- -- -- ----- ------

-- -------------------
----- -------- --------- -
  --- ---- - ----- ------------------
  -- ------- -
    -- -- --- ---------
    ----- ----- - ------------------------ - -- - --- - --
    ----- ---------- - ------
    ---- - ----- ----------------
    -- ----
    ----------------- ----- ----- ------
  -
  ------ -----
-

-- ----
----- -------- -------------- -
  ----- ----- - ----- -----------------
  --- ---- ---- -- ------ -
    ----------------- - -------- ----- ----- ------
  -
-
展开代码

缓存穿透优化

为了避免缓存穿透的发生,可以采取以下几种优化方案:

  1. 对于不存在的键,写入一个空值或一个特殊标识符,表示该键不存在,这样下次请求过来时就只会落在 Redis 缓存中,避免请求数据库;
  2. 过滤掉异常或者不存在的请求;
  3. 使用布隆过滤器,在 Redis 缓存和数据库之间做一层过滤,过滤掉一些不存在于数据库中的请求。
-- -------------------- ---- -------
-- ----
-- ------
----- -------- --------------- -
  --- ---- - ----- ----------------- - ----
  -- ------- -
    -- -----
    ----------------- - --- --- ----- ------
    ------ -----
  -
  ------ -----
-

-- -------
----- -------- --------------- -
  -- ---------------- -
    ------ -----
  -
  --- ---- - ----- ----------------- - ----
  -- ------- -
    ---- - ----- ----------------------
    -- ------- -
      -- -----
      ----------------- - --- --- ----- ------
      ------ -----
    -
    ----------------- - --- ----- ----- ------
  -
  ------ -----
-

-- ----------------------
----- ---------- - -----------------------
----- ---------- - --- ------------ ----- ------------ ----- ---- ---
----- -------- ------------------------------ -
  -- ------ ---------------------------------- ---- -
    ------ -----
  -
  --- ---- - ----- ----------------- - ----
  -- ------- -
    ---- - ----- ----------------------
    -- ------- -
      ----- ------------------------------- ----
      ------ -----
    -
    ----------------- - --- ----- ----- ------
  -
  ------ -----
-
展开代码

缓存击穿优化

为了避免缓存击穿的发生,可以采取以下几种优化方案:

  1. 加入互斥锁,避免缓存并发访问;
  2. 利用 Redis 的自带机制,通过批量获取数据来优化查询。
-- -------------------- ---- -------
-- ----
-- -----
----- -------- --------------- -
  --- ---- - ----- ----------------- - ----
  -- ------- -
    -- ------------------------------
    -- ------ ----------------------- - --- ---- ----- ----- ---- -
      ---- - ----- ----------------------
      -- ------- -
        -- -----
        ----------------- - --- --- ----- ------
        ------ -----
      -
      ----------------- - --- ----- ----- ------
      -- ---
      ----------------------- - ----
    - ---- -
      -- ---------------------------------------
      ----- ---------
      ------ ----- ----------------
    -
  -
  ------ -----
-

-- ------
----- -------- ------------------ -
  -- ----------
  ----- ----------- - ----- ------------------------ -- ------- - -----
  -- --------
  ----- --------- - ---
  ----- ------------- - ---
  ---------------------------- ------ -- -
    -- --------- -
      ---------------------------
    - ---- -
      --------------------
        --- -----------
        ------- -------------------
      ---
    -
  ---
  -- ---------
  ----- ----------- - ----- -------------------------------
  -- ----
  ------------------------ -- -
    ----------------- - -------- --------------------- ----- ------
    -------------------- --- -------- ------- ---- ---
  ---
  -- ----
  ----- ------- - ---
  -------------- -- -
    ----- ---- - ----------------------- -- ------- --- ----
    -- ------ -
      --------------------------
    - ---- -
      -------------------
    -
  ---
  ------ --------
-
展开代码

综上所述,利用 Redis 缓存可以大幅提升网站性能,但也带来了一些问题。通过采取优化方案可以有效避免这些问题,让网站运行更加平稳稳定。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d806e0a941bf7134e534d0

纠错
反馈

纠错反馈