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

缓存三剑客解决方案

缓存三剑客解决方案

1.缓存雪崩

定义:大量缓存数据在同一时间点集体失效,导致所有请求直接穿透到数据库,引发数据库瞬时高负载甚至崩溃。

解决方案:设置过期随机值,避免大量缓存同时失效

// 缓存雪崩防护:随机过期时间 + 双层缓存// 设置随机过期时间(基础时间 + 随机偏移)Random random = new Random();long expire = baseExpire + random.nextInt(5 * 60 * 1000); // 基础5分钟 + 随机5分钟内data = loader.load();setCache(key, data, expire);setCache(backupKey, data, expire * 2); // 备份缓存过期时间更长return data;
}

2. 缓存击穿解决方案

定义:某个热点Key突然失效(如过期或被删除),同时有大量并发请求访问该Key,导致请求全部穿透到数据库。

方案1:互斥锁(分布式锁)

在这里插入图片描述

  @Nullable// todo 3、缓存击穿 -> 互斥锁:只能由一个线程进行缓存构建,其他线程等待,吞吐量较低private Shop huchi(Long id) {String shopJsonStr = stringRedisTemplate.opsForValue().get("cache:shop:" + id);if (StrUtil.isNotBlank(shopJsonStr)) {return JSONUtil.toBean(shopJsonStr, Shop.class);}// 未命中获取锁String tryLockKey = "cache:shop:lock:" + id;Shop shop = null;try {boolean tryLock = getLock(tryLockKey);// 未命中:不断休眠直至获取成功while (!tryLock) {Thread.sleep(50);tryLock = getLock(tryLockKey);}// 获取互斥锁,进行缓存的构建shop = getById(id);if (shop == null) {// 数据库中也不存在时候,进行空字符串缓存stringRedisTemplate.opsForValue().set("cache:shop:" + id, "", 2, TimeUnit.MINUTES);return null;}stringRedisTemplate.opsForValue().set("cache:shop:" + id, JSONUtil.toJsonStr(shop), 2, TimeUnit.MINUTES);} catch (Exception e) {e.getStackTrace();} finally {unLock(tryLockKey);}return shop;}

方案2:逻辑过期(适合高并发读场景)

在这里插入图片描述

@Nullable// todo 3、缓存击穿 -> 逻辑过期:通过设置逻辑过期时间,然后判断是否过期来确定是否进行缓存更新private Shop exLogical(Long id) {ExecutorService executorService = Executors.newFixedThreadPool(10);String shopJsonStr = stringRedisTemplate.opsForValue().get("cache:shop:" + id);// 如果不存在那就是一定不存在if (StrUtil.isBlank(shopJsonStr)) {return null;}//RedisDate redisDate = JSONUtil.toBean(shopJsonStr, RedisDate.class);Shop shop = JSONUtil.toBean((JSONObject) redisDate.getObject(), Shop.class);// 未逻辑过期if (redisDate.getEx().isAfter(LocalDateTime.now())) {return shop;}// 逻辑过期//  缓存重建String tryLockKey = "cache:shop:lock:" + id;boolean tryLock = getLock(tryLockKey);if (tryLock) {// 开启独立的线程去独立的进行缓存executorService.submit(() -> {try {this.saveShopRedis(id, 20L);} finally {unLock(tryLockKey);}});}return shop;}// 手动设置逻辑过期时间private void saveShopRedis(Long id, Long ex) {Shop shop = getById(id);RedisDate redisDate = new RedisDate();redisDate.setEx(LocalDateTime.now().plusSeconds(ex));redisDate.setObject(shop);stringRedisTemplate.opsForValue().set("cache:shop:" + id, JSONUtil.toJsonStr(redisDate));}

3. 缓存穿透解决方案

定义:查询数据库中根本不存在的数据(如非法ID或恶意攻击),导致请求绕过缓存直接访问数据库。

方案1:缓存空对象

@Nullable//  todo 1、解决缓存穿透问题private Shop chaungtou(Long id) {// 缓存穿透解决方案 -> 缓存""空字符冲String shopJsonStr = stringRedisTemplate.opsForValue().get("cache:shop:" + id);if (StrUtil.isNotBlank(shopJsonStr)) {return JSONUtil.toBean(shopJsonStr, Shop.class);}// shopJsonStr == "":代表用户访问的是一个数据库中不存在的数据if (shopJsonStr != null) {// 店铺不存在return null;}Shop shop = getById(id);if (shop == null) {// 数据库中也不存在时候,进行空字符串缓存stringRedisTemplate.opsForValue().set("cache:shop:" + id, "", 2, TimeUnit.MINUTES);return null;}stringRedisTemplate.opsForValue().set("cache:shop:" + id, JSONUtil.toJsonStr(shop), 2, TimeUnit.MINUTES);return shop;}

方案2:布隆过滤器


文章转载自:
http://alderfly.dxwdwl.cn
http://bumpy.dxwdwl.cn
http://bun.dxwdwl.cn
http://allotropism.dxwdwl.cn
http://agenize.dxwdwl.cn
http://alcula.dxwdwl.cn
http://amoebae.dxwdwl.cn
http://blackamoor.dxwdwl.cn
http://brno.dxwdwl.cn
http://cataclastic.dxwdwl.cn
http://antinatalist.dxwdwl.cn
http://authorize.dxwdwl.cn
http://beetleweed.dxwdwl.cn
http://biochemist.dxwdwl.cn
http://caliche.dxwdwl.cn
http://banda.dxwdwl.cn
http://castle.dxwdwl.cn
http://abstersion.dxwdwl.cn
http://ascolichen.dxwdwl.cn
http://cattleman.dxwdwl.cn
http://adlet.dxwdwl.cn
http://chicanismo.dxwdwl.cn
http://authentication.dxwdwl.cn
http://basilic.dxwdwl.cn
http://capsulated.dxwdwl.cn
http://amiably.dxwdwl.cn
http://basophilic.dxwdwl.cn
http://bystreet.dxwdwl.cn
http://aerodrome.dxwdwl.cn
http://afford.dxwdwl.cn
http://www.dtcms.com/a/276193.html

相关文章:

  • 基于YOLO11的垃圾分类AI模型训练实战
  • 计算机毕业设计ssm医院耗材管理系统 基于SSM框架的医疗物资供应链管理平台 医院低值易耗品信息化监管系统
  • 解决MySql8报错:Public Key Retrieval is not allowed
  • 六年级数学知识边界总结思考-上册
  • 苍穹外卖项目日记(day05)
  • JavaScript加强篇——第六章 定时器(延时函数)与JS执行机制
  • matplotlib:散点图
  • CCF CSP第一轮认证一本通
  • 【Fargo】发送一个rtp包的过程3:为什么媒体包发送端检测到扩展,接收端检测不到
  • Rail开发日志_7
  • 9.3 快速调用与标准调用
  • 串口连接工控机
  • Gameplay - 独立游戏Celeste的Player源码
  • 失败的面试经历二(ʘ̥∧ʘ̥)
  • 【赵渝强老师】国产数据库TiDB的代理路由:TiProxy
  • K3S滚动发布Jar
  • TCP详解——各标志位
  • 字母异位词分组
  • 闲庭信步使用图像验证平台加速FPGA的开发:第十一课——图像均值滤波的FPGA实现
  • 家用智能摄像机PRV文件删除的恢复方法
  • 牛客网50题
  • word转pdf、pdf转word在线工具分享
  • C#调用Matlab生成的DLL
  • C#枚举:从基础到高级的全方位解析
  • NLP分词notes
  • 用一张“冰裂纹”石墨烯薄膜,让被动散热也能做 AI 推理——基于亚波长裂纹等离激元的零功耗温度-逻辑门
  • 深度学习图像分类数据集—铜片划痕识别分类
  • 创客匠人:解析创始人 IP 打造对知识变现的深层赋能
  • position: fixed和sticky的区别
  • 子数组最大平均数 I