redis缓存穿透

2022-11-02 15:36:59 浏览数 (1)

ps:想只读有效信息,见红字

正常情况

当在高并发,高性能,降低数据库压力的情况下,首先会选择redis作为缓存机制,当有大量请求需要查询数据库时,为了降低数据库的压力,并提高请求查询性能(redis基于内存,读取速度快),会将数据库的信息缓存到redis中,这样就形成了很好的分层结构,请求可以直接查询redis中缓存的信息,然后返回,就不需要经过数据库,减小了数据库的压力,同时,可以迅速查询到信息,岂不美哉。 先从缓存取数据,娶不到从数据库取,取到了就返回并添加缓存或更新缓存,取不到就返回空。

==正常请求操作==

第4步,当从数据库拿到数据时,一并添加到redis缓存,下次若是相同请求,直接访问redis并返回,大大提升了性能和可用性,持久性。

非正常情况

但有利就有弊,如果请求的数据是数据库中没有的,同样redis中也不会出现此数据缓存,这样当某短时间大量无效请求(数据库无对应数据)访问时,由于redis中没有此数据缓存,请求就给到了数据库,那么压力就来到了数据库这边,可想而知,其中会浪费掉多少性能,若是有心怀**之人故意为之,后果可想而知。所以,这就需要一个很好的解决方案,当大量无效请求(数据库并没有此数据)来访问时,就会导致缓存穿透。 缓存和数据库都娶不到数据,若大量无效请求发起,数据库负载压力过大

==非正常操作(在大量无益请求的场景下)==

第4步变为直接返回null,那么请求一多,全都访问数据库,好嘛,要是网站被攻击了,那数据库就白想活着~

解决方案✍️✍️

1.redis缓存设空(“”)

redis设置key-null,TTL设置短时间 那么就又要考虑了,当一个请求访问时,我们两层都没有相应数据,数据库操作后接着对redis设一个空的键值,那么当我过了段时间又增加了一条数据,正好就是这个请求需要的,当第一步走到redis时直接就死掉了,那么可太不划算了。 所以在缓存设空时尽量TTL一个短时间,防住短时间大量请求即可,谁也不会闲的干这事。

那么我们接下来模拟一下具体场景 下面是操作流程代码块

代码语言:javascript复制
@Override
public Result queryById(Long id) {
    //从redis查询商铺缓存
    String key = "cache:shop" id;
    //根据key拿到数据json块
    String shopJson = stringRedisTemplate.opsForValue().get(key);
    if (StrUtil.isNotBlank(shopJson)) {
        //存在,转化为对应实体类直接返回
        Shop shop = JSONUtil.toBean(shopJson, Shop.class);
        return Result.ok(shop);
    }
    //判断命中的是否为空值,下下面代码存入的value为""空
    if (shopJson!=null) {//等效于shopJson==""
        //返回一个错误信息
        return Result.fail("店铺不存在");

    }

    //不存在根据id查数据库
    Shop shop = getById(id);
    if (shop == null) {
        //数据库中不存在,将null写入redis,并设置TTL
        stringRedisTemplate.opsForValue()
        .set(key,"",2, TimeUnit.MINUTES);
        return Result.fail("店铺不存在");

    }
    //存在,存入redis
    stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),60, TimeUnit.MINUTES);

    return Result.ok(shop);
}

一条请求,这里是根据id来查询,此时设置id为0,数据库并不存在这条数据。观察到,返回了不存在json信息

而且redis是没有缓存的,所以执行了相应数据库的sql操作,数据库并没有id为0的数据,所以下一步就是增加redis空缓存

此时,redis增加了一个key表示店铺id为0的空缓存,右上角TTL还剩·114秒(设置的为2分钟)

这样就能在短时间在缓存层面拦截大量无意义请求。

2.布隆过滤

利用hash算法计算数据库数据得到byte数组,当请求来访问先经过布隆过滤器,根据此数组0和1判断数据是否存在,存在就放行到redis否则拒绝。

0 人点赞