Redis缓存三剑客

发布时间 2024-01-07 16:19:05作者: 自学Java笔记本

缓存穿透

概念:查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求查数据库从而使得数据库压力过大,宕机
image

解决方案一:

缓存空数据,查询返回的数据为空,扔把这个空结果进行缓存例如格式:{key:xxx,value:null}
优点:简单
缺点:消耗内存,可能会发生不一致的问题

代码实现:

  // 解决缓存击穿问题,将查询结果写入缓存中,同时当数据库查询结果为null时写入缓存中
    @Override
    public Shop findById(Long id) {
        // 先从redis中查询数据
        String shop = stringRedisTemplate.opsForValue().get(RedisContants.SHOP_KEY + id);

        // 初始化 ObjectMapper
        ObjectMapper objectMapper = new ObjectMapper();
        if (StringUtils.isNoneBlank(shop)){
            try {
                return objectMapper.readValue(shop,Shop.class);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }

        if (shop != null){
            // 这里要返回错误信息,例如xxx不存在
            return null;
        }
        // 这里需要去从数据库中查询
        Shop shopObj = shopMapper.findById(id);
        if (shopObj != null){
            String writeValueAsString = null;
            try {
                writeValueAsString = objectMapper.writeValueAsString(shopObj);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            stringRedisTemplate.opsForValue().set(RedisContants.SHOP_KEY+id,writeValueAsString,1, TimeUnit.DAYS);
            return shopObj;
        }else {
            // 表示数据库中也没有,将 null 存储在 Redis 中
            stringRedisTemplate.opsForValue().set(RedisContants.SHOP_KEY + id, "", 10, TimeUnit.SECONDS);
        }
        return null;
    }

解决方案二:布隆过滤器

image

了解即可

总结

什么是缓存穿透,怎么解决?
查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求查数据库从而使得数据库压力过大,宕机。

缓存击穿

概念:给某一个key设置了过期时间,当key过期的时候,恰好这时间点对这个key有大量的并发请求过来,这些并发请求可能会瞬间把DB压垮。
主要是热点key的问题,例如查询数据库花费了一些时间,在这个时间段多个线程都访问了数据库导致压力过大
image
解决方案:互斥锁,逻辑过期

互斥锁

image

描述:
当缓存失效时,不立即去load db,先使用入Redis的setnx去设置一个互斥锁,当操作成功返回时在进行数据库的操作并回设缓存,否则重试get缓存的方法。

缓存雪崩

缓存雪崩是指在同一时间大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力,
image

解决方案:

  • 给不同的key的TTL添加随机值
  • 利用Redis集群提高服务的可用性
  • 给缓存业务添加降级限流策略,nginx或网关
  • 给业务添加多级缓存,Guava 或Caffeine

描述:
缓存雪崩意思时设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩,与缓存击穿的区别:雪崩时很多key,击穿是某一个key缓存

解决方案主要是可以将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

双写一致

当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致

  • 读操作:缓存命中,直接返回;缓存未命中查询数据库,写入缓存,设定超时时间
  • 读操作:延迟双删

删除缓存----> 修改数据库 ------>延时,删除缓存

无论是先删除缓存,还是先修改数据库,都会导致数据不一致性的问题,根本原因取决于线程是交替进行的。
所以采用双删策略。