当前位置: 首页 > 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://www.xdnf.cn/news/1108477.html

相关文章:

  • 【C语言】回调函数、转移表、qsort 使用与基于qsort改造冒泡排序
  • 利用docker部署前后端分离项目
  • 敏捷开发方法全景解析
  • SQL server之版本的初认知
  • C#枚举:从基础到高级的全方位解析
  • 《通信原理》学习笔记——第一章
  • 《Spring 中上下文传递的那些事儿》Part 11:上下文传递最佳实践总结与架构演进方向
  • 基于MCP的CI/CD流水线:自动化部署到云平台的实践
  • Vue Vue-route (5)
  • Adobe Illustrator关于图标创建的问题
  • 【跟我学运维】chkconfig jenkins on的含义
  • 初等行变换会改变矩阵的什么?不变改变矩阵的什么?求什么时需要初等行变换?求什么时不能初等行变换?
  • 回归(多项式回归)
  • 电网通俗解析术语2:一二次设备关联
  • 【PycharmPyqt designer桌面程序设计】
  • Effective Modern C++ 条款9:优先考虑别名声明而非typedef
  • Socket到底是什么(简单来说)
  • 【Elasticsearch】昂贵算法与廉价算法
  • 史上最全 MySQL 锁详解:从理论到实战,一篇搞定所有锁机制
  • 网络编程员工管理系统
  • 【数据分析】03 - Matplotlib
  • 【Elasticsearch 】search_throttled
  • 力扣-19. 删除链表的倒数第N个节点
  • Windows环境下解决Matplotlib中文字体显示问题的详细指南
  • Git入门教程
  • JVM与系统性能监控工具实战指南:从JVM到系统的全链路分析
  • 虚拟现实的镜廊:当技术成为存在之茧
  • Unity VR手术模拟系统架构分析与数据流设计
  • 深度学习图像分类数据集—害虫识别分类
  • [论文阅读] 人工智能 + 软件工程 | AI助力软件可解释性:从用户评论到自动生成需求与解释