21.缓存穿透

缓存穿透

客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会到达数据库。会造成数据库宕机。

解决方案

1.缓存空对象

例如查询数据的id,发现数据库中没有,那么就在redis中缓存空对象。但是会有额外的内存消耗, 如果有很多数据都查不到,就会在redis中缓存很多null对象,垃圾数据。如果一开始数据在db中不存在,在redis中缓存了空对象。后来该数据有了,由于redis已经缓存了null对象,造成数据短期的不一致

数据不一致可以采用两种办法,第一,给redis中缓存的key设置ttl过期时间,过一段时间数据将会一致。第二,当数据产生了插入db的后,也更新下缓存,将原来的缓存的null对象给覆盖掉。

2.布隆过滤

布隆过滤是一种算法,在客户端与redis之间有一个拦截布隆过滤器。

优点:内存占用少,没有多余的key。缺点:实现复杂,存在误判可能。

 缓存空对象的代码实现

@Override
    public Result queryById(Long id) {
        String key = RedisConstants.CACHE_SHOP_KEY + id;
        //从redis中查询商铺缓存
        String shopJsonStr = stringRedisTemplate.opsForValue().get(key);
        //redis中有数据直接返回
        if(StrUtil.isNotBlank(shopJsonStr)) {
            Shop shop = JSONUtil.toBean(shopJsonStr, Shop.class);
            return Result.ok(shop);
        }
        //判断命中的是否为空值
        if(shopJsonStr != null) {
            //说明命中空字符串,不会去查数据库
            return Result.fail("店铺不存在");
        }

        //redis中没有数据,继续查询数据库
        Shop shop = getById(id);
        if(ObjectUtil.isNull(shop)) {
            //将空值写入redis
            stringRedisTemplate.opsForValue().set(key, "", RedisConstants.CACHE_NULL_TTL, TimeUnit.MINUTES);
            //数据库没有查询到数据,返回错误
            return Result.fail("店铺不存在");
        }
        //数据库中查询到数据,存入redis,再返回数据;设置超时时间
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);
        return Result.ok(shop);
    }
public static final Long CACHE_NULL_TTL = 2L;

主动的方式解决缓存穿透

1.增强id的复杂度,避免被猜测id的规律。

2.做好数据的基础格式校验。

3.加强用户权限校验,只有登录的用户有权限的用户才能访问。

4.做好热点参数的限流。

遗留问题:布隆过滤器的代码实现? 可以基于redisson实现。

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1. 缓存穿透:指查询一个不存在的数据,由于缓存中没有,导致请求直接到达数据库。这种情况可能是攻击者恶意攻击,也可能是查询一个不存在的数据。 解决方案:使用布隆过滤器,将已有的数据的哈希值存储在布隆过滤器中,在查询数据时,先判断数据是否存在于布隆过滤器中,如果不存在,直接返回查询失败,避免请求直接到达数据库。 2. 缓存击穿:指缓存中存在的数据,在某个时间点过期时,恰好在这个时间点有大量的请求访问这个数据,导致请求直接达到数据库,造成数据库压力过大。 解决方案:在设置缓存时,给缓存数据设置一个过期时间,同时使用互斥锁(例如Redis的分布式锁)来控制过期时间到达时,只有一个线程去重新生成缓存数据,其他线程等待该线程完成缓存数据的生成。 3. 缓存雪崩:指缓存中的数据集中在某一个时间段内过期失效,导致大量的请求直接到达数据库,造成数据库压力过大。 解决方案:在设置缓存时,给缓存数据设置一个随机的过期时间,避免所有缓存数据在同一时间失效。同时,使用多级缓存架构,例如一级缓存为本地缓存,二级缓存为分布式缓存,三级缓存为数据库,当一级缓存失效时,先从二级缓存中获取数据,如果二级缓存也失效了,再从三级缓存中获取数据。这样可以避免所有缓存数据在同一时间失效,并且减轻数据库的压力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卷土重来…

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值