美文网首页
Redis缓存穿透、缓存雪崩、缓存击穿解决方案

Redis缓存穿透、缓存雪崩、缓存击穿解决方案

作者: 等等ChEnH | 来源:发表于2019-10-30 19:32 被阅读0次

    一、缓存处理流程

    前台请求,后台先从缓存中取数据,取到直接返回结果,取不到从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。


    缓存处理流程

    二、缓存穿透

    缓存穿透,是指查询一个数据库一定不存在的数据。正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据,每次又都不会进行缓存。假如有恶意攻击,就可以利用这个漏洞,对数据库造成压力,甚至压垮数据库。

    解决方案:
    1、接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
    2、从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击

    public Goods searchGoodsById(Long goodsId){
            Object obj = redisTemplate.opsForValue().get(String.valueOf(goodsId));
            if(obj != null){//缓存中查询到数据
                return (Goods)obj;
            }
            
            Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
            System.out.println("=============主键ID:" + goodsId + "进行了数据库查询=============");
            
            if(goods != null){//数据库中查询到结果,放入缓存
                redisTemplate.opsForValue().set(String.valueOf(goodsId), goods, 60,TimeUnit.MINUTES);
            }else{
                redisTemplate.opsForValue().set(String.valueOf(goodsId), null, 30 ,TimeUnit.SECONDS);//对空值缓存30s
            }
    
            return goods;
     }
    

    三、缓存雪崩

    缓存雪崩,是指在某一个时间段,缓存集中过期失效。而对这批过期缓存的查询都落到了数据库上,对于数据库而言查询数据量巨大,引起数据库压力过大甚至down机。做电商项目的时候,一般是采取不同分类商品,缓存不同周期。在同一分类中的商品,加上一个随机因子。这样能尽可能分散缓存过期时间,而且,热门类目的商品缓存时间长一些,冷门类目的商品缓存时间短一些,也能节省缓存服务的资源。

    public Goods searchGoodsById(Long goodsId){
            Object obj = redisTemplate.opsForValue().get(String.valueOf(goodsId));
            if(obj != null){//缓存中查询到数据
                return (Goods)obj;
            }
    
            Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
            System.out.println("=============主键ID:" + goodsId + "进行了数据库查询=============");
    
            if(goods != null){//数据库中查询到结果,放入缓存
                Random r = new Random();
                int time = 3600;
                if(goods.getGoodsCategory().equals("女装")){//热门商品缓存时间设置
                    time = 3600 + r.nextInt(3600);
                }
                if(goods.getGoodsCategory().equals("图书")){//冷门商品缓存时间设置
                    time = 600 + r.nextInt(600);
                }
                redisTemplate.opsForValue().set(String.valueOf(goodsId), goods, time,TimeUnit.SECONDS);
                
            }else{
                redisTemplate.opsForValue().set(String.valueOf(goodsId), null, 30 ,TimeUnit.SECONDS);
            }
    
        }
    

    比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网,很有可能瞬间就把数据库压垮。

    三、缓存击穿

    缓存击穿是指一个key非常热点,缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。做电商项目的时候,把这货定义为“爆款”。

    解决方案:
    1、设置热点数据永远不过期。
    2、mutex key互斥锁,暂时未用到

    相关文章

      网友评论

          本文标题:Redis缓存穿透、缓存雪崩、缓存击穿解决方案

          本文链接:https://www.haomeiwen.com/subject/hglavctx.html