Redis缓存穿透、缓存击穿、缓存雪崩的原理和解决办法

Redis缓存穿透、缓存击穿、缓存雪崩的原理和解决办法
最新回答
魔怪小姐

2024-01-31 00:26:52

Redis缓存穿透、缓存击穿、缓存雪崩的原理和解决办法如下

一、缓存穿透

  • 原理:当查询的key在缓存中不存在,且数据库中也不存在对应数据时,每次请求都会直接穿透缓存层访问数据库,导致数据库压力骤增。这种情况常见凳谨于恶意攻击或数据未初始化场景。

  • 解决办法

    布隆过滤器:通过布隆过滤器预判数据是否存在,拦截无效请求。布隆过滤器是一种空间效率高的概率型数据结构,可快速判断元素是否在集合中(可能存在误判,但可接受)。

    缓存空值:对查询结果为空的数据也进行缓存,设置较短过期时间。例如查询ID为-1的用户信息不存在时,将null或空数组缓存30秒,避免重复查询数据库。

(示意图:缓存穿透导致数据库压力激增)

二、缓存击穿

  • 原理:某个热点key在缓存过期瞬间,大量并发请求同时穿透缓存访问数据库,导致数据库瞬间压力过大。例如秒杀活动开始时,商品库存key过期引发大量查询。

  • 解决办法

    互斥锁(Mutex Key):使用Redis的SETNX命令实现分布式锁,仅允许一个请求查询数据库并更新缓存,其他请求等待或重试。示例代码逻辑如下:

    if ($this->redis->setnx($setnx_key, 1, $expire)) { // 查询数据陆码库并更新缓存 $this->redis->del($setnx_key); // 释放锁} else { sleep(10); // 等待后重试 self::fetch();}

    逻辑过期:缓存数据中存储逻辑过期时间,请求发现过期时启动后台线程异步更新缓存,避免阻塞主请求。

三、缓存雪崩

  • 原理:大量缓存key在同一时间集中过期,或缓存服务宕机,导致所有请求直接访问数据库,造枣悉基成系统崩溃。例如设置所有缓存过期时间为凌晨3点,此时大量请求同时穿透。

  • 解决办法

    随机过期时间:为缓存key的过期时间添加随机值(如30±5秒),分散过期时间点,降低集中失效概率。

    多级缓存:采用本地缓存(如Caffeine)与Redis分布式缓存结合,本地缓存无过期时间,仅当Redis失效时触发本地缓存更新。

    缓存标记:设置缓存标记key(如prize_list_cash),标记过期时触发数据库查询,而实际数据key(如prize_list)设置更长过期时间。示例代码:

    $cash_result = $this->redis->get($this->cash_key);if (!$cash_result) { $this->redis->set($this->cash_key, 1, $this->expire); // 查询数据库并更新数据key,设置2倍过期时间 $this->redis->set($this->redis_key, $result, $this->expire * 2);}

    熔断降级:当数据库压力过大时,临时返回降级数据(如默认值或缓存旧数据),保障系统可用性。

总结对比

  • 穿透:针对不存在的key,需拦截无效请求或缓存空值。
  • 击穿:针对热点key过期,需加锁或异步更新。
  • 雪崩:针对批量key过期,需分散时间或多级缓存。

实际场景中需结合业务特点选择方案,例如高并发秒杀系统优先采用互斥锁+随机过期时间,而内容管理系统可能更适合缓存标记+多级缓存。