缓存雪崩、击穿、穿透的原因与解决方案

本文深入探讨缓存雪崩、缓存击穿和缓存穿透现象,分析其成因及对系统稳定性的影响,并提供有效的应对策略,包括使用分布式锁、预热缓存等方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

缓存雪崩

雪崩的现象:

   DB 接受到的请求量过大,导致 DB 下线或数据查询变慢,并且相关依赖该库的接口都抛出错误,导致大量服务挂掉。短时间内重启后,依然会被大量请求给打下线,导致一段时间内服务不可用。

原因:

   在较短时间段内,大量的缓存数据集中过期了。如在代码中,短时间内对大批量的热点数据设置了 30min 过期,而 30min 后,大批量的热点数据被清理掉,导致大量的数据请求到 DB 。

解决方案:

  1. 对热点数据的过期时间,再添加一个随机值( Math.random()*1000 ),避免出现极短的时间内大量缓存数据被删除的情况。

  2. 限流降级,控制进入的流量大小,降级部分请求即不处理


缓存击穿

击穿的原因:

   缓存击穿是指某一个热点数据过期了,但同时又有大批量其他请求来访问该数据,导致大量的请求到了 DB 上。它与缓存雪崩相似,缓存雪崩指的是多个 key ,而缓存击穿指的是某一个 key。

解决方案:

  1. 适当的延长该类型 key 过期时间
  2. 使用分布式锁,让一个请求去加载数据到缓存中,避免大量请求到达 DB。实现代码可参考如下:
    private String getKey(String key){
        String value = stringRedisTemplate.opsForValue().get(key);
        if(StringUtils.isEmpty(value)){//缓存过期了
            RLock lockKey = redisson.getLock("lockKey");
            try {
                //4秒内等待尝试获取锁;如果获取成功,加3s的锁(该类型的锁每隔3s/3s,检测锁是否存在;如果锁存在重新设置超时时间为3s,如果不存在,则不做处理)。
                boolean lockSuccess = lockKey.tryLock(4, 3, TimeUnit.SECONDS);
                if(lockSuccess){//加锁成功,当前线程去读取 DB 并设置缓存
                    value = db.get(key);
                    stringRedisTemplate.opsForValue().set(key, value, 10,TimeUnit.SECONDS);
                }else {//加锁失败,证明已有其他线程执行了上面两行代码
                    TimeUnit.MILLISECONDS.sleep(200);
                    getKey(key);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lockKey.unlock();
            }
        }
        return value;
    }

缓存穿透

穿透的现象:

   穿透是大量异常参数请求打到了 DB,例如对大量不存在的数据进行查询的请求。对于小一点的单机系统,利用 Postman + 缓存穿透的漏洞就可以把 DB 打挂。

原因:

   查询一个一定不存在的数据,由于缓存不命中,导致每次都要到持久化存储层去查询数据。比如使用 id < 0 或 id = Integer.MAX_VALUE来查询数据。

解决方案:

  1. 对于接受查询参数的接口,做非法参数校验,避免请求到数据库。
  2. 对缓存和 DB 中都不存在的数据,考虑将对应的缓存 value 设置为 null,并将有效期设置短一点。使用该方案时需要考虑,避免缓存与 DB 数据不一致的问题,需要在数据设值时,去删除或者刷新缓存中对应的值。
  3. 缓存穿透是建立在大量请求的基础上,可以考虑在网关层(Nginx)限制单个 ip 的 QPS 来控制部分异常情况。
  4. 可以使用 Bloom Filter 过滤数据不存在的请求,Cuckoo Filter(布谷鸟过滤器)可以更好的解决缓存穿透问题。更多关于 Bloom Filter 的介绍

缓存预热

缺少预热的现象:

   在某个考试系统中,开考时间为 10 点整,大量考生该时刻涌入,部分考生在获取题目时,需要读取 DB,导致 DB 压力过大,考生被迫等待卡顿一段时间。

原因

   题库数据在使用前,未被加载到 Redis ,DB 压力过大导致响应变慢。

解决方案:

   为避免出现用户在使用热点数据时,先去 DB 查,然后再保存到 Redis 中的过程,可以结合 缓存预热和分布式锁 来添加缓存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值