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

相关文章:

  • BaseDao 通用查询方法设计与实现
  • Raft 代码分析
  • 区块链平台之以太坊深入解读:技术、经济与生态的全面解析
  • el-tree 懒加载 loadNode
  • 可穿戴智能硬件在国家安全领域的应用
  • 【设计模式】装饰(器)模式 透明装饰模式与半透明装饰模式
  • Lua ADB 接口文档
  • GGE Lua 详细教程
  • C# 接口(派生成员作为实现)
  • nginx反向代理实现跨域请求
  • 分层架构的C++高并发内存池性能优化
  • STP生成树协议
  • Eureka实战
  • Linux - 安全排查 3
  • 带货视频评论洞察 Baseline 学习笔记 (Datawhale Al夏令营)
  • 【读书笔记】《C++ Software Design》第一章《The Art of Software Design》
  • 【大模型面试】50道大型语言模型(LLM)面试问题汇总,看完少走99%弯路!
  • 不止于监控:深入剖析OpenTelemetry的可观察性生态体系
  • LeetCode 3169.无需开会的工作日:排序+一次遍历——不需要正难则反,因为正着根本不难
  • 暑期前端训练day6
  • 历史数据分析——云南白药
  • 连接池的核心接口和常用属性
  • 基于大模型的鼻咽癌全周期预测及诊疗优化研究报告
  • SQL新手入门详细教程和应用实例
  • 零基础 “入坑” Java--- 九、类和对象(二)
  • 芯片验证之验证策略
  • 【MogDB】一种基于ctid分片并发查询以提升大表查询性能的方式
  • 68 指针的减法操作
  • 【Datawhale AI夏令营】Task2 笔记:MCP Server开发的重难点
  • 使用包管理工具CocoaPods、SPM、Carthage的利弊与趋势