0


Redis三大难点之缓存击穿

文章目录

缓存击穿

缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。

解决方案

  • 互斥锁
  • 逻辑过期

在这里插入图片描述

基于互斥锁方式解决缓存击穿问题

设计思想

在这里插入图片描述

代码实现

/**
     * 缓存穿透解决方案
     *
     * @param id id
     * @return ResponseEntity<Object>
     */@OverridepublicResponseEntity<Object>getUserByIdWithMutex(String id){// 从redis中根据key查询用户列表信息String user =(String) redisTemplate.opsForValue().get("user:"+ id);// 如果用户信息不为null、""、"\t\n",则存在,转化为Issa,返回if(StrUtil.isNotBlank(user)){Issa issa =JSONUtil.toBean(user,Issa.class);returnResponseEntity.ok(issa);}// 如果user不为null,说明user为空字符串,直接返回if(user !=null){returnResponseEntity.status(400).body("没有用户信息");}Issa userById =null;try{// 获取锁boolean lockFlag =BooleanUtil.isTrue(redisTemplate.opsForValue().setIfAbsent("lock:"+ id,"1",10,TimeUnit.SECONDS));// 如果没有得到锁,则休眠50ms,递归调用该方法if(!lockFlag){Thread.sleep(50);returngetUserByIdWithMutex(id);}// 如果得到了锁,则去数据库查询
            userById = userMapper.getUserById(id);// 如果为null,说明数据库没有该数据,为了避免缓存穿透,存上""空字符串,并以TTL过期时间作为兜底方案if(userById ==null){// 将空值写入redis
                redisTemplate.opsForValue().set("user:"+ id,"",1,TimeUnit.MINUTES);// 返回错误信息returnResponseEntity.status(400).body("没有用户信息");}// 如果不为null,将该数据缓存到redis服务器
            redisTemplate.opsForValue().set("user:"+ id, userById,60,TimeUnit.SECONDS);}catch(InterruptedException e){
            e.printStackTrace();}finally{// 最后释放锁
            redisTemplate.delete("lock:"+ id);}// okreturnResponseEntity.ok(userById);}

基于逻辑过期方式解决缓存击穿问题

设计思想

在这里插入图片描述

代码实现

privatestaticfinalExecutorService CACHE_REBUILD_EXECUTOR =Executors.newFixedThreadPool(10);/**
     * 缓存穿透解决方案
     *
     * @param id id
     * @return ResponseEntity<Object>
     */@OverridepublicResponseEntity<Object>getUserByIdWithLogicalExpire(String id){// 从redis中根据key查询用户列表信息String user =(String) redisTemplate.opsForValue().get("user:"+ id);// 如果没有用户信息if(StrUtil.isBlank(user)){returnResponseEntity.status(400).body("没有用户信息");}RedisData redisData =JSONUtil.toBean(user,RedisData.class);Issa issa =JSONUtil.toBean((JSONObject) redisData.getData(),Issa.class);LocalDateTime expireTime = redisData.getExpireTime();if(expireTime.isAfter(LocalDateTime.now())){returnResponseEntity.ok(issa);}boolean lockFlag =BooleanUtil.isTrue(redisTemplate.opsForValue().setIfAbsent("lock:"+ id,"1",10,TimeUnit.SECONDS));if(lockFlag){
            CACHE_REBUILD_EXECUTOR.submit(()->{try{// 查询数据库Issa userById = userMapper.getUserById(id);// 重建缓存// 设置逻辑过期RedisData newRedisData =newRedisData();
                    newRedisData.setData(issa);
                    newRedisData.setExpireTime(LocalDateTime.now().plusSeconds(TimeUnit.SECONDS.toSeconds(60)));// 写入Redis
                    redisTemplate.opsForValue().set("user:"+ id,JSONUtil.toJsonStr(newRedisData));}catch(Exception e){thrownewRuntimeException(e);}finally{// 释放锁
                    redisTemplate.delete("lock:"+ id);}});}// okreturnResponseEntity.ok(issa);}
/**
 * 处理逻辑过期时间的类
 *
 * @author issavior
 */@DatapublicclassRedisData{privateLocalDateTime expireTime;privateObject data;}

**

💥《核心技术系列专栏汇总》💥

**

  • 《Java系核心技术》
  • 《中间件核心技术》
  • 《微服务核心技术》
  • 《云原生核心技术》
  • 《通用业务实现集》
  • 《一起去大厂系列》
  • 《开源项目o s s a》

需要

大厂面试题

简历模版

电子书

所有源码

等关注👇【公众号】👇回复「 1024 」即可。

标签: 缓存 redis java

本文转载自: https://blog.csdn.net/CSDN_SAVIOR/article/details/125124941
版权归原作者 步尔斯特 所有, 如有侵权,请联系我们删除。

“Redis三大难点之缓存击穿”的评论:

还没有评论