天天看点

Redis缓存穿透和雪崩问题

什么是缓存穿透和雪蹦?

缓存是为了减轻数据库的压力、提升数据的查询效率。但是按照一般逻辑,数据在缓存中没有取到就会去数据库中获取,如果大量的访问都没有在缓存中获取到数据,就有“穿透”的问题,进而带来缓存雪蹦的问题。

1、大并发环境下,第一次访问缓存,发现缓存中没有数据,然后所有线程都会去访问数据库,这样就造成缓存短暂失效,这就是“缓存穿透”。缓存穿透的危害:导致大量的请求直接到数据库,导致数据库的承载压力过大导致宕机。
2、数据库查询不到这个数据,在redis中保存的key所对应的value就为null。那代码逻辑也会出现穿透。先判断key是否在缓存中存在,只要存在key,不论value是否为null,都认为缓存中有 数据,主要有数据就不要再访问数据库。

解决缓存穿透问题

总结:

1、双重检测机制(在锁的内外都进行缓存查询,没有查到在进行数据库查询)。

2、不论查询到的数据是否为null,都将它写入缓存。

3、避免缓存中的null键值撑满整个内存,所以需要给null键值设置过期时间。

4、提前分析项目中可能出现并发的数据,提前将这些数据写入缓存。(在tomcat容器启动的时候写入缓存)

5、key的设计,要唯一标识一条数据,不能被其他数据覆盖。

Object obj = null;
        //第一层:解决缓存穿透:通过数据库没有的数据进行穿透
        if(redisTemplate.hasKey(key)){
            //1、读取缓存
            obj = getStringCache(key);
            return obj;
        }else {
            //线程开始排队
            synchronized (this) {
                //第二层:解决缓存穿透:通过数据库没有的数据进行穿透
                if (redisTemplate.hasKey(key)) {
                    //双重检测锁机制,第二层避免排队的线程再次查询数据库,导致数据库的压力。需要在锁内部再次查询缓存
                    obj = getStringCache(key);
                    return obj;
                } else {
                    //2、缓存中没有数据,读取数据库数据库
                    obj = goodsMapper.queryGoods();
                    Gson gson = new Gson();
                    String json = gson.toJson(obj);
                    if(obj == null){
                        //如果是空key,避免空key(无效数据)将内存消耗完,设置过期时间,定期删除。
                        //注意:时间也不宜过长,时间过长会导致无效数据短期内也会撑满整个内存。
                        addStringCacheEX(key,json,5);
                    }else {
                        //3、将数据库取出的数据写入缓存,方便第二次从缓存中取数据
                        addStringCache(key,json);
                    }
                    obj = json;
                }
            }
        }
        return obj;
    }
           

继续阅读