缓存穿透、雪崩、击穿

  • 一、三大问题
  • 1.缓存穿透
  • 2.缓存雪崩
  • 3.缓存击穿
  • 4.怎么办?
  • 二、锁
  • 1.本地锁
  • 2.分布式锁
  • 3. 本地锁在分布式下怎样呢?
  • 1).复制多个product启动类,实现product集群
  • 2).启动4个product
  • 3).压力测试
  • 4). 总结


一、三大问题

1.缓存穿透

redissearch社区版_redissearch社区版

2.缓存雪崩

redissearch社区版_redissearch社区版_02

3.缓存击穿

redissearch社区版_缓存_03

4.怎么办?

穿透:空结果缓冲(null)
雪崩:设置过期时间(随机值)
击穿:加锁

二、锁

1.本地锁

synchronized (this) ,JUC(lock)
synchronized (this) 可以锁代码块、锁方法

//从redis缓存获得数据
    //todo: OutOfDirectMemoryError,堆外内存溢出
    @Override
    public Map<String, List<Category2Vo>> getCatalogJson() {
        //把数据放入redis,从redis获得数据[序列化,反序列化],因为JSON跨平台兼容
        //1.从redis缓存获得数据
        String catalogJson = redisTempalte.opsForValue().get("catalogJson");
        //2.如果redis缓存有数据,使用缓存数据;否则查询数据库,再把数据放入redis缓存,并且转为json数据
        if (StringUtils.isEmpty(catalogJson)) {
            Map<String, List<Category2Vo>> catalogJsonFromDb = getCatalogJsonFromDb();
            System.out.println("缓存不命中。。。。将要查询数据库。。");
            return catalogJsonFromDb;
        }
        System.out.println("缓存命中。。。。直接返回。。");
        //返回值变为需要的map数据
        Map<String, List<Category2Vo>> result = JSON.parseObject(catalogJson, new TypeReference<Map<String, List<Category2Vo>>>() {
        });
        return result;
    }
//2.获取二级、三机分类(从数据库查询并封装分类数据)
    public Map<String, List<Category2Vo>> getCatalogJsonFromDb() {
        synchronized (this) {
            //1.从redis缓存获得数据
            String catalogJson = redisTempalte.opsForValue().get("catalogJson");
            if (!StringUtils.isEmpty(catalogJson)) {
                Map<String, List<Category2Vo>> result =
                        JSON.parseObject(catalogJson, new TypeReference<Map<String, List<Category2Vo>>>() {});
                return result;
            }
            System.out.println("查询数据库。。。。。"+Thread.currentThread());

            //将数据库的多次查询, 变成一次
            //nginx动静分离
            List<CategoryEntity> selectList = baseMapper.selectList(null);
            //1).查询所有一级分类
            List<CategoryEntity> categorys1 = getParent_cid(selectList, 0L);
            //2).封装数据
            Map<String, List<Category2Vo>> parent_cid = categorys1.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
                //2.1查询每个一级分类的二级分类(k,v都为某个一级分类)
                List<CategoryEntity> categoryEntities = getParent_cid(selectList, v.getCatId());
                //2.2封装上面结果   (item2,item3为二级、三机分类)
                List<Category2Vo> category2Vos = null;
                if (categoryEntities != null) {
                    category2Vos = categoryEntities.stream().map(item2 -> {
                        Category2Vo category2Vo = new Category2Vo(v.getCatId().toString(), null, item2.getCatId().toString(), item2.getName());
                        //2.2.1 封装二级分类的三机分类
                        List<CategoryEntity> level3category = getParent_cid(selectList, item2.getCatId());
                        //2.2.2 把三机分类数据封装到Category3Vo,并且封装到二级分类Category2Vo
                        if (level3category != null) {
                            List<Category2Vo.Category3Vo> collect = level3category.stream().map(item3 -> {
                                Category2Vo.Category3Vo category3Vo = new Category2Vo.Category3Vo(item2.getCatId().toString(), item3.getCatId().toString(), item3.getName());
                                return category3Vo;
                            }).collect(Collectors.toList());
                            category2Vo.setCatalog3List(collect);
                        }
                        return category2Vo;
                    }).collect(Collectors.toList());
                }
                return category2Vos;
            }));
//2.把查到的数据放入缓存,序列化
            String s = JSON.toJSONString(parent_cid);
            redisTempalte.opsForValue().set("catalogJson", s, 1, TimeUnit.DAYS);
            return parent_cid;
        }
    }

图片

redissearch社区版_List_04

2.分布式锁

redissearch社区版_List_05

3. 本地锁在分布式下怎样呢?

本地锁:synchronized ,lock
分布式锁:

1).复制多个product启动类,实现product集群

redissearch社区版_缓存_06


redissearch社区版_缓存_07


redissearch社区版_redissearch社区版_08


redissearch社区版_缓存_09

2).启动4个product

redissearch社区版_redis_10

3).压力测试

redissearch社区版_数据_11


redissearch社区版_缓存_12


redissearch社区版_redis_13

4). 总结

分布式下,使用本地锁,锁不住所有服务(实例)