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

Redis-更新策略

目录

缓存更新策略

主动更新策

Cache Aside patten

缓存穿透

缓存空对象​

缓存雪崩​

缓存击穿​编

互斥锁​

逻辑过期​


缓存更新策略

淘汰方式触发者时机数据是否还新鲜典型用法
内存淘汰(Eviction)Redis 自己内存达到 maxmemory 上限与新鲜度无关,只问“谁最不常用”所有 key 通用,兜底
超时剔除(Expiration)时间轮+Redis到达 TTL可能已过期,但还没被删除常规缓存,SET 时 EX/PX
主动更新(Proactive Refresh)业务/后台任务数据库一变更就立刻推/刷新缓存永远最新高并发读,0 击穿方案

主动更新策略

#模式读链路写链路一致性性能代码侵入典型场景
01Cache Aside 旁路缓存未命中→查库→回填先写库→再删缓存最终一致读快写慢互联网读多写少,标配
02Read/Write Through 直写未命中→由缓存层自己回源由缓存层同步写库强一致读写均衡低(靠中间层)本地缓存、嵌入式 KV
03Write Behind 回写只读缓存,命中即可只写缓存→异步刷库弱一致(可能丢)写极快最低计数器、日志、点击流

Cache Aside patten

时序先删缓存再写库(错误示范)先写库再删缓存(推荐)
T1线程 A 删掉缓存线程 A 更新数据库
T2线程 B 发现缓存为空线程 B 读到旧缓存(仍有效)
T3线程 B 把旧库值重新刷进缓存 → 永久脏数据线程 A 删除缓存 → 下次读会重新加载新值
结果100% 出现旧值回填,一定不一致只有 T2-T3 之间极短的脏读,且可二次删兜底
先更新数据库 = 先锁定“真相”;再删缓存 = 让缓存“重新问真相”。
反过来先删缓存,会让缓存有机会把“过期的真相”再次当成“真相”写回去,必现脏数据;而先写库再删缓存,只会出现毫秒级脏读,且可用延迟二次删把风险压到几乎为零。

缓存穿透

缓存穿透(Cache Penetration)
定义:查询一个在缓存数据库里都必然不存在的数据,请求每次都会穿透缓存直接打到数据库,导致缓存形同虚设。

解决方案:

缓存空对象(Null Cache)
发现数据库返回 null 时,仍然把 null 写进 Redis,并给一个短 TTL(30~300 s)。

布隆过滤器(Bloom Filter)
预先把所有合法 ID 哈希进一个位数组(百万级 ≈ 1 MB)。

由于存在哈希碰撞,可能导致布隆放行后查询不存在的情况。

缓存空对象

在未命中Redis的时候,如果数据库中也不存在,则在Redis中存入一个空值。

在Redis判断命中的时候,如果命中的是空值则之间返回错误信息。
shopJson !=null  本质就是shopJson 为空。

 public Result queryById(Long id) {String key=CACHE_SHOP_KEY+id;//1. 从redis查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get(key);//2. 判断是否存在if (StrUtil.isNotBlank(shopJson)) {//3. 存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}//判断是否为空值if (shopJson != null) {return Result.fail("店铺不存在");}//4. 不存在,根据id查询数据库Shop shop = getById(id);//5.不存在,返回错误if (shop == null) {//将空值写入RedisstringRedisTemplate.opsForValue().set(key, "",CACHE_NULL_TTL,TimeUnit.MINUTES);//返回错误信息return Result.fail("店铺不存在");}//6. 存在,写入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL,TimeUnit.MINUTES);//7. 返回return Result.ok(shop);}

缓存雪崩

缓存击穿

互斥锁

public Shop queryWithMutex(Long id){String key=CACHE_SHOP_KEY+id;//1. 从redis查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get(key);//2. 判断是否存在if (StrUtil.isNotBlank(shopJson)) {//3. 存在,直接返回return JSONUtil.toBean(shopJson, Shop.class);}//判断是否为空值if (shopJson != null) {return null;}//4. 建立缓存重建//4.1 获取互斥锁String locakKey="lock:shop"+id;Shop shop=null;try {boolean isLock = tryLock(locakKey);//4.2 判断锁是否获取成功if(!isLock){//4.3 失败,返回错误或者重试Thread.sleep(50);return queryWithMutex(id);}//4.4 成功,根据id查询数据库shop = getById(id);//模拟耗时Thread.sleep(200);//5. 不存在,返回错误if (shop == null) {//将空值写入redisstringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL,TimeUnit.MINUTES);//返回错误信息return null;}//6. 存在,写入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL,TimeUnit.MINUTES);} catch (InterruptedException e) {throw new RuntimeException(e);}finally {//7. 释放互斥锁unLock(locakKey);}//8. 返回return shop;}

逻辑过期

  • 并发不高、允许短暂等待互斥锁(简单、强一致)

  • 超高并发、体验优先、可接受几秒旧值逻辑过期(异步重建,零阻塞)


文章转载自:

http://E8Q20u7n.rzpkt.cn
http://Wo3y05k2.rzpkt.cn
http://RtlSbdqv.rzpkt.cn
http://Bs3c9SnJ.rzpkt.cn
http://GlKnzqk2.rzpkt.cn
http://MnI4kUw9.rzpkt.cn
http://LXKrJo3U.rzpkt.cn
http://xDIupGdv.rzpkt.cn
http://uAeGJ2Gh.rzpkt.cn
http://x0PHLnTF.rzpkt.cn
http://S0GQeh54.rzpkt.cn
http://cZk5RkbG.rzpkt.cn
http://OMSAybnP.rzpkt.cn
http://d8gs5nTr.rzpkt.cn
http://KwoGk4FB.rzpkt.cn
http://mKQCkrSk.rzpkt.cn
http://bUa0wqaj.rzpkt.cn
http://gUcK41Pd.rzpkt.cn
http://bPeFamc6.rzpkt.cn
http://TEShFt0j.rzpkt.cn
http://VsHY2LH3.rzpkt.cn
http://HpqN8mJs.rzpkt.cn
http://YgtClhoH.rzpkt.cn
http://OllyuEot.rzpkt.cn
http://DHyMZqJj.rzpkt.cn
http://EDOpIoiU.rzpkt.cn
http://vgfKxpgi.rzpkt.cn
http://8N3Ia79Y.rzpkt.cn
http://m9xZEP8Y.rzpkt.cn
http://MfOUxx1y.rzpkt.cn
http://www.dtcms.com/a/387742.html

相关文章:

  • 7、二叉树-四种遍历方式
  • 双指针:逛画展
  • 数字孪生能源大数据云平台建设方案
  • WPSOffice引用的组件
  • 按键分区和非按键分区对窗口计算的影响
  • 2020年下半年 系统架构设计师 综合知识
  • 传感器与传感网 | 第一章:传感器与感知技术
  • 在Jupyter Notebook里面渲染pyecharts无法显示
  • 在 React 项目里下载 CSV 文件常见的两种方式
  • 【脑电分析系列】第15篇:脑电功能连接性与脑网络分析(二):Granger因果性、图论指标与复杂网络构建
  • SpringMVC 系列博客(一):基础概念与注解开发入门
  • AI+Playwright+Pytest 自动化测试方案:优势、劣势与实战融合
  • docker启动Nginx并配置SSL自动续期.md
  • OpenStack 学习笔记(三):存储与计算核心组件管理实践
  • Linux文件IO与文件系统深度解析:从系统调用到文件系统原理
  • 如何在 2025 年绕过 Cloudflare 人工检查?
  • 【pycharm】index-tts2:之三 :ubuntu24.04 体验tts demo
  • vivado中DDR4 仿真模型的获取
  • 《RocketMQ 2025 实战指南:从消息丢失 / 重复消费 / 顺序消费到事务消息,一篇搞定生产级问题(附完整代码)》
  • 十二、vue3后台项目系列——设置路由守卫,获取角色权限,获取角色路由列表、页面请求进度条
  • 6个AI论文网站排行,实测
  • Dioxus基础介绍和创建组件
  • 基于粒子群算法的山地环境无人机最短路径规划研究(含危险区域约束的三维优化方法)
  • ardupilot开发 --- 无人机数学模型与控制律分解 篇
  • 海外代理IP服务器平台测评,Tik Tok多账号运营稳定IP服务支持
  • 【面板数据】省及地级市农业新质生产力数据集(2002-2025年)
  • Linux的常用命令总结
  • Egg.js:企业级 Node.js 框架的优雅实践
  • vue中v-model绑定计算属性
  • 查看磁盘分区并新建一个分区,挂载分区