redis缓存穿透问题解决方案

缓存穿透是什么意思

简单说就是查询的缓存key在redis中不存在,穿透到了数据库层。

正常情况下使用redis缓存应该是下面这样的,用户访问到达服务,服务查询redis,如果redis中存在则直接返回。如果redis中不存在,则查询数据库,数据库返回结果。但此时会有一个问题,就是这个条件在数据库中也查不到数据,所以服务拿到了空数据就不会缓存到redis中,然后下次再使用这个条件来访问服务,服务就会再次查询redis和数据库。在流量较大时,则会有压垮数据库的风险。

redis缓存穿透问题解决方案_第1张图片

如何解决缓存穿透问题

  1. 缓存空对象
    真正造成问题的是查询数据库也没数据,也就代表这个key对应的数据现在是不存在的,那我们只需要把这个key缓存到redis就好了,给一个null值,示例代码如下。(代码为《Redis开发与运维》书中第11.4章给出的代码,因为代码确实很简单,就直接拿来用了…)

    String get(String key){
        String cacheValue = cache.get(key);
        if (StringUtils.isBlank(cacheValue)) {
            //  从存储中获取
            String storageValue = storage.get(key);
            cache.set(key, storageValue);
            //  如果存储数据为空,需要设置一个过期时间 (300 秒 )
            if (storageValue == null) {
                cache.expire(key, 60 * 5);
            }
            return storageValue;
            } else {
            //  缓存非空
            return cacheValue;
        }
    }
    
  2. 使用布隆过滤器拦截

    可以理解成用一个集合来缓存有数据的key,如果集合里没有这个key,则默认数据不存在,不去查询数据库。

    布隆过滤器可以自己实现,也可以用现有的方案。常用的Jeds并没有提供布隆过滤器,比较通用的方案是google的guava工具包,下面给出使用的伪代码。

    //构造布隆过滤器,并指定误判率,这里指定0.01,需要注意的是误判率越低占用的内存空间就会越大,100代表过滤器长度
    private static BloomFilter<Integer> bloomFilter =BloomFilter.create(Funnels.integerFunnel(), 100,0.01);
    //判断是否在过滤器中,上面构造过滤器时指定的数据类型是int,所以下面参数也必须是数字
    bloomFilter.mightContain(2)
    

哪种方式比较好

如果系统流量不大,可以考虑第一种方式,实现简单,使用起来也简单。需要注意的就是在缓存空对象到redis时需要给数据设置一个过期时间,否则可能会导致内存溢出。

但如果流量比较大,这种方式就不太合适了,因为缓存太多的key也会导致内存溢出。此时可以考虑使用布隆过滤器的方式来解决缓存穿透的问题,需要注意的是布隆过滤器本身存在一定的误判率,需要结合业务需求来设置误判率和过滤器的数数据长度,需要注意的是误判率越低,占用的内存也是越多的,需要结合实际环境来设置参数。

你可能感兴趣的:(缓存,Redis)