当前位置: 首页 > news >正文

Redis面试二“缓存击穿是什么”

条件

缓存击穿是应为Redis某个缓存数据设置了过期时间,而刚好有大并发数据请求这个数据,导致DB有大量请求,引发DB崩溃。

第一种方法就是设置互称锁

当缓存失效时不立即删除缓存而是用setnx设置一个互斥锁,当操作完成后在load db,并回设缓存,否则重试get缓存方法,这样就减少了直接大量访问DB的请求。

实现

@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleDao, SysRoleDO> implements SysRoleService {@Resourceprivate RedissonClient redissonClient;@Overridepublic List<SysRoleDO> test() throws Exception {Object roles = redissonClient.getBucket("role").get();// 先查询缓存,缓存中有则直接返回if (Objects.nonNull(roles)) {return JSON.parseArray(roles.toString(), SysRoleDO.class);}RLock lock = redissonClient.getLock("role-lock");boolean isLock = lock.tryLock();if (isLock) {// 获取到锁查询数据库,并将查询结果放入缓存try {Object roleList = redissonClient.getBucket("role").get();// 双重检查锁,当多个线程同时判断到缓存中取不到值,上一个获取到锁的线程已经将数据放入缓存,下一个线程直接取缓存if (Objects.nonNull(roleList)) {return JSON.parseArray(roleList.toString(), SysRoleDO.class);}// 查询数据库List<SysRoleDO> list = this.list();// 将数据放入缓存redissonClient.getBucket("role").set(list, 60L, TimeUnit.SECONDS);return list;} finally {lock.unlock();}}int retryTimes = 3;Object roleList = null;// 当缓存中取不到值时sleep300毫秒,最多循环3次while (Objects.isNull(roleList) && retryTimes > 0) {// 休眠300ms后递归TimeUnit.MILLISECONDS.sleep(300L);roleList = redissonClient.getBucket("role").get();retryTimes--;}// 循环等待后缓存中取到值直接返回,仍然取不到值则抛异常if (Objects.nonNull(roleList)) {return JSON.parseArray(roleList.toString(), SysRoleDO.class);}throw new RuntimeException("查询异常");}
}

第二种解决缓存击穿的实现就是设置key逻辑过期时间

1.在设置key的时候过期时间字段并一块存入缓存,不给当前key设置过期时间。

2.当查询的时候在redis中判断是否过期,条件就是字段设置时间与当前时间对比。

3.如果过期就开通另一个线程进行数据同步,当前线程正常返回数据,但数据就不是最新的时老的数据不能保证强一致。

实现

//逻辑过期public Shop queryWithLogicalExpire(Long id) {String key = CACHE_SHOP_KEY + id;//1.从redis查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if (StrUtil.isBlank(shopJson)) {//3.未命中return null;}//4.命中,需要先把json反序列化为对象RedisData redisData = JSONUtil.toBean(shopJson, RedisData.class);Shop shop = (Shop) redisData.getData();LocalDateTime expireTime = redisData.getExpireTime();//5.判断是否过期if (expireTime.isAfter(LocalDateTime.now())) {//5.1还未过期return shop;}//5.2已经过期,需要缓存重建//6.缓存重建//6.1获取互斥锁String lockKey = LOCK_SHOP_KEY + id;boolean isLock = tryLock(lockKey);//6.2判断是否获取锁成功if (isLock) {// 6.3成功,开启独立线程,实现缓存重建CACHE_REBUILD_EXECUTOR.submit(() -> {try {//重建缓存this.saveShop2Redis(id, 20L);} catch (Exception e) {e.printStackTrace();} finally {//释放锁unlock(lockKey);}});}//6.4返回过期的店铺信息//7.返回return shop;}

总结

如果要求数据的强一致测使用分布式锁,如果要求高可用就使用逻辑过期就可以了。

http://www.lryc.cn/news/172747.html

相关文章:

  • python使用apscheduler每隔一段时间自动化运行程序
  • 2023 Sui Builder House全球之旅圆满收官
  • OpenCV自学笔记二十三:K近邻算法
  • ChatGLM-中英对话大模型-6B试用说明
  • 小白入门pytorch(一)
  • 【STM32笔记】HAL库I2C通信配置、读写操作及通用函数定义
  • Direct3D模板缓存
  • 在windows上执行ssh-keygen报错Bad permissions
  • 给Proxmox VE 虚拟机分配巨大分区惹麻烦
  • 数学建模——统计回归模型
  • C++【个人笔记1】
  • 博通强迫三星签不平等长约,被韩处罚1亿元 | 百能云芯
  • 版本控制 Sourcetree
  • 题目 1059: 二级C语言-等差数列
  • HarmonyOS 如何使用异步并发能力进行开发
  • 时间格式化时候HH和hh的区别
  • aliyunoss上传图片
  • 动手吧,vue数字动画
  • Android12之仿Codec2.0实现传递编解码器组件本质(四十六)
  • MongoDB【部署 04】Windows系统实现MongoDB多磁盘存储
  • ruoyi框架使用自定义用户表登录
  • 计算机视觉与深度学习-卷积神经网络-卷积图像去噪边缘提取-卷积-[北邮鲁鹏]
  • JS手动实现发布者-订阅者模式
  • 【含面试题】MySQL死锁日志分析与解决的Java代码实现
  • 解决方案:TSINGSEE青犀+智能分析网关助力智慧仓储智能化监管
  • 进程间通信
  • Ubuntu 22.04.3 LTS安装
  • 记一次manjaro-i3系统sogoupinying候选词无法正常显示中文(变方框了)问题解决方案
  • Lua学习笔记:词法分析
  • flask服务鉴权