缓存3-redis的缓存击穿、穿透、雪崩--分布式测试

一、三大问题

1.缓存穿透

在这里插入图片描述

2.缓存雪崩

在这里插入图片描述

3.缓存击穿

在这里插入图片描述

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;
        }
    }

图片
# 啊

2.分布式锁

在这里插入图片描述

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

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

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2).启动4个product

在这里插入图片描述

3).压力测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4). 总结

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Redis 缓存击穿穿透雪崩是三个常见的缓存问题: 1. 缓存击穿:指一个非常热门的 key,在缓存过期的一刻同时有大量的并发请求,这些请求发现缓存过期一般会从后端数据库中加载数据并写入缓存,这时候大并发的请求可能会直接“穿透缓存层,直接请求到数据库,导致数据库压力过大,出现宕机等情况。 2. 缓存穿透:指查询一个不存在的 key,由于缓存中没有数据,所以每次请求都会穿透缓存层,请求到数据库,这同样会导致数据库压力过大,出现宕机等情况。 3. 缓存雪崩:指在缓存过期的一刻,大量的请求涌进来,这些请求发现缓存过期一般会从后端数据库中加载数据并写入缓存,如果此时缓存层和数据库层的压力过大,很可能导致缓存层和数据库层同时宕机,整个系统不可用。 为了避免这些问题,可以采取以下措施: 1. 对于缓存击穿,可以设置热点数据永不过期或者加锁,以保证在缓存失效期间只有一个请求去查询数据库。 2. 对于缓存穿透,可以使用布隆过滤器过滤掉不存在的 key 请求,或者设置不存在的 key 对应的 value 为一个默认值,以避免频繁查询数据库。 3. 对于缓存雪崩,可以采用分布式缓存架构,将缓存层和数据库层分开部署在不同的服务器上,以避免单点故障。同时,可以设置缓存失效时间随机化,避免缓存同时失效,还可以设置熔断机制,当缓存层出现异常时,自动切换到数据库层查询数据。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值