21.缓存穿透

发布于:2024-08-26 ⋅ 阅读:(103) ⋅ 点赞:(0)

缓存穿透

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

解决方案

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实现。


网站公告

今日签到

点亮在社区的每一天
去签到