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);}熔断降级:当数据库压力过大时,临时返回降级数据(如默认值或缓存旧数据),保障系统可用性。
总结对比:
实际场景中需结合业务特点选择方案,例如高并发秒杀系统优先采用互斥锁+随机过期时间,而内容管理系统可能更适合缓存标记+多级缓存。