缓存击穿(热点key问题)

1.什么是缓存击穿?

缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂(意味着对数据库压力相对较大)的key突然失效了(可以理解为redis的缓存突然无了),无数的请求访问会在瞬间给数据库带来巨大的冲击。

2.解决方案

1.互斥锁:当同个业务不同线程访问redis未命中时,先获取一把互斥锁,然后进行数据库操作,此时另外一个线程未命中时,拿不到锁,等待一段时间后重新查询缓存,此时之前的线程已经重新把数据加载到redis之中了,线程二就直接缓存命中。这样就不会使得大量访问进入数据库

2.优缺点

优点:没有额外的内存消耗,保证一致性,实现简单

缺点:线程需要等待,性能受影响,可能有死锁风险

2.逻辑过期:给缓存设置一个逻辑过期时间,什么意思呢?缓存本来在redis之中,正常情况下除了主动更新它是不会变的,为了防止缓存击穿,我们以一种预判或者说保守的方式,主动设置一个过期时间,当然这个时间过期了,缓存里面的数据是不会消失的,但是我们只需要根据这个假设的过期时间。来进行经常的动态的缓存数据的更新。可以对缓存击穿起一定的预防作用

优点:线程无需等待,性能较好

缺点:不保证一致性,有额外内存消耗,实现复杂

实现代码

//互斥锁public Shop queryWithMutex(Long id){//1.从redis查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + id);//2.判断是否存在if(StrUtil.isNotBlank(shopJson)){//3.存在直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return JSONUtil.toBean(shopJson,shop.getClass());}/* 判断命中的是否为空 */if (shopJson!=null){//返回一个错误信息return null;}//4,实现缓存重建//4.1 获取互斥锁String lockKey="lock:shop"+id;Shop shop = null;try {boolean isLock = tryLock(lockKey);//4.2 判断是否获取成功if (!isLock){//4,3 失败 则休眠并重试Thread.sleep(50);queryWithMutex(id);}//4.4 成功 根据id查询数据库shop = getById(id);
//        5.不存在 返回错误if (shop==null){//将空值写入redis(防止缓存击穿问题)stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY+ id,"",2L,TimeUnit.MINUTES);return  null;}//        6.存在,写入redisstringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY+ id,JSONUtil.toJsonStr(shop),RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);} catch (InterruptedException e) {throw  new RuntimeException(e);} finally {//        7,释放互斥锁unlock(lockKey);}
//        7.返回return shop;}
//逻辑过期解决方案public Shop queryWithLogicalExpire(Long id){//1.从redis查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + id);//2.判断是否存在if(StrUtil.isBlank(shopJson)){//3如果不存在 直接返回nullreturn null;}//4命中 需要先把json反序列化为对象RedisData redisData = JSONUtil.toBean(shopJson, RedisData.class);JSONObject data = (JSONObject)redisData.getData();Shop shop = JSONUtil.toBean(data, Shop.class);LocalDateTime expireTime = redisData.getExpireTime();//判断是否过期if (expireTime.isAfter(LocalDateTime.now())){// 5.1 未过期 直接返回商铺信息return shop;}
//        5.2 已过期 需要缓存重建
//        6.缓存重建
//        6.1获取互斥锁String lockKey="lock:shop"+id;boolean isLock = tryLock(lockKey);
//        6.1判断是否获取锁成功if(isLock){//todo   6.2成功 开启独立线程实现缓存重建CACHE_REBUILD_EXECUTOR.submit(()->{try {//重建this.saveShopRedis(id,20L);} catch (Exception e) {throw new RuntimeException(e);} finally {//释放锁unlock(lockKey);}});}
//        6.3失败 ,直接返回旧的商铺return shop;}

什么是缓存击穿?如何解决?相关推荐

  1. Redis针对缓存击穿的解决方法-互斥锁

    参考至:Java岗大厂面试百日冲刺 - 日积月累,每日三题[Day2] -- Redis篇1_陈哈哈的菜园子-CSDN博客 缓存穿透:指缓存和数据库中都没有的数据,导致所有的请求都打到数据库上,然后数 ...

  2. 应对缓存击穿的解决方法

    一.什么样的数据适合缓存? 分析一个数据是否适合缓存,我们要从访问频率.读写比例.数据一致性等要求去分析. 二.什么是缓存击穿 在高并发下,多线程同时查询同一个资源,如果缓存中没有这个资源,那么这些线 ...

  3. redis缓存雪崩,缓存穿透,缓存击穿的解决方法

    一.缓存雪崩 缓存雪崩表示在某一时间段,缓存集中失效,导致请求全部走数据库,有可能搞垮数据库,使整个服务瘫痪. 使缓存集中失效的原因: 1.redis服务器挂掉了. 2.对缓存数据设置了相同的过期时间 ...

  4. Redis 缓存常见问题 :缓存雪崩,缓存击穿,缓存穿透,缓存预热

    文章目录 缓存雪崩 缓存击穿 缓存穿透 缓存预热 缓存雪崩 缓存雪崩指的是在短时间内,有大量缓存的键同时过期,由于缓存过期,导致此时所有的请求就直接查询数据库,而数据库很难抵挡这样巨大的压力,严重情况 ...

  5. redis缓存穿透、缓存雪崩、缓存击穿、并发竞争

    关注微信公众号"虾米聊吧",每天更新一篇技术文章,文章内容涵盖架构师成长必经之路应掌握的技术,一起学习,一起交流. 缓存穿透.缓存雪崩.缓存击穿.并发竞争是缓存最常见的几个问题,接 ...

  6. golang groupcache重复抑制(singeflight)机制,防止缓存击穿

    缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞. groupcach ...

  7. 缓存穿透、缓存击穿、缓存雪崩概述缓存一致性的解决方案

    背景: 缓存一致性的产生原因是为了提高系统的吞吐量,通常会把一些即时性.数据强一致性要求不高的,或者访问量大且更新频率不高(读多写少) 的数据从数据库中读取并放到缓存中,提高系统的IO速度,从而提高吞 ...

  8. redis面试:缓存雪崩、缓存击穿、缓存穿透

    缓存系统的三大问题 缓存雪崩 问题 所谓雪崩就是原来有所支撑的冰雪,某一瞬间失去依托,瞬间涌下来. 对比高并发系统,如果缓存系统故障,大量的请求无法从缓存完成数据请求,就全量冲向磁盘数据库系统,导致数 ...

  9. Redis:缓存雪崩,缓存击穿,缓存穿透,缓存预热

    缓存雪崩. 缓存雪崩指的是在短时间内,有大量缓存的键同时过期,由于缓存过期,导致此时所有的请求就直接查询数据库,而数据库很难抵挡这样巨大的压力,严重情况下就会导致数据库被大流量打死,直接宕机. 缓存雪 ...

  10. Redis 缓存击穿(失效)、缓存穿透、缓存雪崩怎么解决?

    欢迎关注方志朋的博客,回复"666"获面试宝典 原始数据存储在 DB 中(如 MySQL.Hbase 等),但 DB 的读写性能低.延迟高. 比如 MySQL 在 4 核 8G 上 ...

最新文章

  1. Castle.ActiveRecord的嵌套事务处理
  2. webpack.config.js====插件purifycss-webpack,提炼css文件
  3. 模拟退火算法解决TSP(python实现 110+行代码)【gif生成】
  4. Promise的用简要使用方式
  5. 利用闭包实现onclick事件传递参数
  6. linux qq多进程客户端,基于多进程QQ聊天软件设计.doc
  7. 将2019拆分成三个整数的平方和
  8. Laravel短信mysql_使用 Laravel 实现阿里云短信服务队列
  9. HUE配置文件hue.ini 的hbase模块详解(图文详解)(分HA集群和非HA集群)
  10. 依赖注入的三种方式_Spring IoC是如何进行依赖注入的
  11. spring框架Annotation之CRUD
  12. 2.6 HDFS存储原理
  13. 软件工程专业学python_笨办法学Python(0)
  14. y等于根号x用c语言程序表示出来,c语言描述x和y都大于或等于z的表达式是
  15. IC数字常见问题(一)时钟
  16. 手游传奇刷元宝_战神传奇手游刷元宝方法技巧大全
  17. 二维码图片生成工具C#winform源码
  18. 每日一书丨手把手教你构建一个通用的智能风控平台
  19. 阿里云扩容云盘(CentOS 7系统)
  20. 静态数码管和动态数码管

热门文章

  1. 3D人脸识别技术原理概述
  2. 团队管理核心-提高团队绩效
  3. 2021重庆江北中学高考成绩查询,重庆市江北中学高2021届学子高考百日誓师大会点燃青春梦想...
  4. 自定义插件实现网易云音乐首页图片轮播
  5. linux yum iso镜像文件,linux yum配置本地iso镜像
  6. 2018.10.15-2018.10.20读书摘录批注
  7. 银联 php hex2bin,php 实现银联商务H5支付的示例代码
  8. import mtcnn cannot import name ‘get_config’ from ‘tensorflow.python.eager.context’
  9. 【域泛化】2022 IJCAI领域泛化教程报告
  10. 云计算入门——IT架构九重天