Redis之缓存更新策略

news2025/5/23 5:39:41

缓存更新策略

在这里插入图片描述

文章目录

  • 缓存更新策略
    • 一、策略对比
    • 二、常见的缓存更新策略
    • 三、如何选择策略
    • 四、实际应用示例
    • 五、使用 Cache-Aside + TTL 的方式,实现缓存商铺信息详情
      • 1.引入StringRedisTemplate
      • 2.将查询商铺信息加入缓存
      • 3.更新商铺信息时移除缓存
      • 总结
    • 六、注意事项

一、策略对比

内存淘汰超时剔除主动更新
说明不用自己维护,
利用Redis的内存淘汰机制,
当内存不足时自动淘汰部分数据。下次查询时更新缓存。
给缓存数据添加TTL时间,
到期后自动删除缓存。
下次查询时更新缓存。
编写业务逻辑,
在修改数据库的同时,更新缓存
一致性一般
维护成本

业务场景

  • 低一致性需求:使用内存淘汰机制。例如商铺类型的查询缓存
  • 高一致性需求:主动更新,并以超时剔除作为兜底方案。例如店铺详情查询的缓存

二、常见的缓存更新策略

  1. Cache Aside Pattern旁路缓存模式):由缓存的调用者,在更新数据库的同时更新缓存。
    • 原理
      • 读操作:先查询缓存,若命中则直接返回;未命中则从数据库加载数据并写入缓存。
      • 写操作:先更新数据库,再删除缓存(或更新缓存)。
    • 优点:简单易实现,适用于大多数场景。
    • 缺点:可能存在短暂的数据不一致(如并发写入导致脏数据)。
    • 场景:读多写少、对一致性要求不高的场景。
  2. Read / Write Through Pattern读穿/写穿):缓存与数据库整合为一个服务,由服务来维护一致性。调用者调用该服务,无需关心缓存一致性问题。
    • 读穿透(Read-Through)
      • 当缓存未命中时,由缓存服务自动从数据库加载数据并回填缓存 。
    • 写穿透(Write-Through)
      • 数据更新时,同时写入缓存和数据库,保证两者同步。
    • 优点:对业务透明,数据一致性高。
    • 缺点:写操作延迟较高,依赖缓存服务的可靠性。
    • 场景:强一致性要求的场景。
  3. Write Behind Caching Pattern异步写回):调用者只操作缓存,由其他线程异步地将缓存数据持久化到数据库,保证最终一致性。
    • 原理
      • 写操作仅更新缓存,异步批量将数据持久化到数据库。
    • 优点:写性能极高,减少数据库压力。
    • 缺点:存在数据丢失风险(如系统崩溃时为同步完成的数据)。
    • 场景:允许短暂不一致、写密集型场景(如日志系统)。
  4. 被动更新(TTL刷新)
    • 原理
      • 为缓存设置过期时间(Time-To-Live,TTL),到期后自动失效并从数据库重新加载。
    • 优点:实现简单,避免长期脏数据。
    • 缺点:无法主动控制更新实际,可能出现缓存雪崩(大量缓存同时失效)。
    • 场景:数据变动频率较低的场景。
  5. 主动更新(事件驱动)
    • 原理
      • 当数据库数据变更时(如通过消息队列或出发期),主动通知应用层更新或删除对应缓存。
    • 优点:实时性高,减少无效查询。
    • 缺点:依赖外部系统协同,复杂度较高。
    • 场景:分布式系统中强一致性要求的场景(如电商库存更新)。

注意在使用Cache Aside Pattern方式的工程中,操作缓存和数据库时有三个问题需要考虑

  1. 删除缓存还是更新缓存?
    • 更新缓存:每次更新数据库都更新缓存,无效写操作较多
    • 删除缓存【推荐】:更新数据库时让缓存失效,查询时再更新缓存
  2. 如何保证缓存与数据库的操作同时成功或同时失败?
    • 单体系统:将缓存与数据库操作放在一个事务
    • 分布式系统,利用TCC等分布式事务方案
  3. 先操作缓存还是先操作数据库
    • 先删除缓存,再操作数据库
    • 先操作数据库,再删除缓存 【推荐】

三、如何选择策略

  • 数据一致性要求:强一致性选 Write-Through 或主动更新;弱一致性可选 Cache-Aside 或 TTL。
  • 读写比例:读多写少优先 Cache-Aside;写多考虑 Write-Behind。
  • 系统复杂度:简单场景用 TTL 或 Cache-Aside;复杂场景用事件驱动。
  • 性能需求:高频写入可用 Write-Behind 降低延迟。

四、实际应用示例

  • 电商商品详情页:使用 Cache-Aside + TTL,配合消息队列主动更新热点商品。
  • 社交点赞数统计:采用 Write-Behind 异步更新数据库,保证快速响应。
  • 全局配置信息:Read-Through 确保每次读取都是最新配置。

五、使用 Cache-Aside + TTL 的方式,实现缓存商铺信息详情

1.引入StringRedisTemplate

    @Resource
    private StringRedisTemplate stringRedisTemplate;

2.将查询商铺信息加入缓存

命中
未命中
存在
不存在
开始
提交商铺id
从Redis查询商铺缓存
判断缓存是否命中
返回商铺信息
结束
根据id查询数据库
判断商铺是否存在
将商铺数据写入Redis
返回404
    @Override
    public Result queryById(Long id) {
        // 1.从redis查询商铺缓存
        String key = CACHE_SHOP_KEY + id;
        String shopJson = stringRedisTemplate.opsForValue().get(key);
        // 2.判断是否存在
        if (StrUtil.isNotBlank(shopJson)) {
            // 3.存在,直接返回
            Shop shop = JSONUtil.toBean(shopJson, Shop.class);
            return Result.ok(shop);
        }
        // 4.不存在,根据id查询数据库
        Shop shop = getById(id);
        if (shop == null) {
            // 5.数据库不存在,返回错误
            return Result.fail("店铺不存在!");
        }
        // 6.存在,写入redis,加入过期时间
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);
        return Result.ok(shop);
    }

3.更新商铺信息时移除缓存

    @Override
    public Result update(Shop shop) {
        if (shop.getId() == null) {
            return Result.fail("店铺id不能为空!");
        }
        // 1.更新数据库
        updateById(shop);
        // 2.删除缓存
        stringRedisTemplate.delete(CACHE_SHOP_KEY + shop.getId());
        return Result.ok();
    }

总结

使用 Cache-Aside + TTL 缓存更新策略的最佳实践方案:

  1. 低一致性需求:使用Redis自带的内存淘汰机制
  2. 高一致性需求:主动更新,并以超时剔除作为兜底方案
    • 读操作:
      • 缓存命中则直接返回
      • 缓存未命中则查询数据库,并写入缓存,设定超时时间
    • 写操作:
      • 先写数据库,然后再删除缓存
      • 要确保数据库与缓存操作的原子性

六、注意事项

  • 缓存穿透:恶意请求不存在的 key,可通过布隆过滤器防御。
  • 缓存雪崩:大量 Key 同时失效,需设置随机 TTL 或禁用失效时间。
  • 缓存击穿:热点 Key 失效瞬间高并发,可用互斥锁(Mutex Luck)保护。

缓存更新策略的选择需结合业务场景、数据特点和技术架构综合权衡,没有绝对的最优解,只有最适合的方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2336818.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【leetcode100】杨辉三角

1、题目描述 给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中,每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]示例 2: 输入: numRows 1 输出: [[1]…

Selenium2+Python自动化:利用JS解决click失效问题

文章目录 前言一、遇到的问题二、点击父元素问题分析解决办法实现思路 三、使用JS直接点击四、参考代码 前言 在使用Selenium2和Python进行自动化测试时,我们有时会遇到这样的情况:元素明明已经被成功定位,代码运行也没有报错,但…

OpenStack Yoga版安装笔记(十九)启动一个实例(Self-service networks)

1、概述 1.1 官方文档 Launch an instancehttps://docs.openstack.org/install-guide/launch-instance.html 《OpenStack Yoga版安装笔记(十四)启动一个实例》文档中,已经按照Option1: Provider networks创建网络。 本文按照Option2&#…

数学教学通讯杂志数学教学通讯杂志社数学教学通讯编辑部2025年第6期目录

课程教材教法 “课程思政”视域下的高中数学教学探索与实践——以“函数概念的发展历程”为例 赵文博; 3-617 PBL教学模式下高中统计教学的探索与实践——以“随机抽样(第一课时)”为例 陈沛余; 7-10 “三新”背景下的高中数学教学困境与应对…

C#容器源码分析 --- Dictionary<TKey,TValue>

Dictionary<TKey, TValue> 是 System.Collections.Generic 命名空间下的高性能键值对集合&#xff0c;其核心实现基于​​哈希表​​和​​链地址法&#xff08;Separate Chaining&#xff09;。 .Net4.8 Dictionary<TKey,TValue>源码地址&#xff1a; dictionary…

在 Visual Studio Code 中安装通义灵码 - 智能编码助手

高效的编码工具对于提升开发效率和代码质量至关重要。 通义灵码作为一款智能编码助手&#xff0c;为开发者提供了全方位的支持。 本文将详细介绍如何在 Visual Studio Code&#xff08;简称 VSCode&#xff09;中安装通义灵码&#xff0c;以及如何进行相关配置以开启智能编码…

idea报错java: 非法字符: ‘\ufeff‘解决方案

解决方案步骤以及说明 BOM是什么&#xff1f;1. BOM的作用2. 为什么会出现 \ufeff 错误&#xff1f;3. 如何解决 \ufeff 问题&#xff1f; 最后重新编译&#xff0c;即可运行&#xff01;&#xff01;&#xff01; BOM是什么&#xff1f; \ufeff 是 Unicode 中的 BOM&#xff0…

PHY芯片与网络变压器接线设计指南——不同速率与接口的硬件设计原则

一、PHY与网络变压器的核心作用 • PHY芯片&#xff08;物理层芯片&#xff09; • 功能&#xff1a;实现数据编码&#xff08;如Manchester、PAM4&#xff09;、时钟恢复、链路协商&#xff08;Auto-Negotiation&#xff09;。 • 接口类型&#xff1a;MII/RMII/GMII/RGMII/…

【学习笔记】计算机网络(八)—— 音频/视频服务

第8章 互联网上的音频/视频服务 文章目录 第8章 互联网上的音频/视频服务8.1概述8.2 流式存储音频/视频8.2.1 具有元文件的万维网服务器8.2.2 媒体服务器8.2.3 实时流式协议 RTSP 8.3 交互式音频/视频8.3.1 IP 电话概述8.3.2 IP电话所需要的几种应用协议8.3.3 实时运输协议 RTP…

linux: 文件描述符fd

目录 1.C语言文件操作复习 2.底层的系统调用接口 3.文件描述符的分配规则 4.重定向 1.C语言文件操作复习 文件 内容 属性。所有对文件的操作有两部分&#xff1a;a.对内容的操作&#xff1b;b.对属性的操作。内容是数据&#xff0c;属性其实也是数据-存储文件&#xff0c…

记录一次后台项目的打包优化

文章目录 前言分析问题寻找切入点根据切入点逐一尝试cdn引入node包遇到的一些问题记录最终结果 前言 优化&#xff0c;所有开发者到一定的程度上&#xff0c;都绕不开的问题之一 例如&#xff1a; 首页加载优化白屏优化列表无限加载滚动优化&#xff0c;图片加载优化逻辑耦合…

问题记录(四)——拦截器“失效”?null 还是“null“?

拦截器“失效”&#xff1f;null 还是"null"&#xff1f; 问题描述 这个问题本身并不复杂&#xff0c;但是却是一个容易被忽略的问题。 相信大家在项目中一定实现过强制登录的逻辑吧&#xff0c;巧了&#xff0c;所要介绍的问题就出现在测试强制登录接口的过程中&am…

图论整理复习

回溯&#xff1a; 模板&#xff1a; void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择&#xff1a;本层集合中元素&#xff08;树中节点孩子的数量就是集合的大小&#xff09;) {处理节点;backtracking(路径&#xff0c;选择列表); // 递归回溯&#xff…

C++修炼:vector模拟实现

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

案例-索引对于并发Insert性能优化测试

前言 最近因业务并发量上升,开发反馈对订单表Insert性能降低。应开发要求对涉及Insert的表进行分析并提供优化方案。   一般对Insert 影响基本都在索引,涉及表已按创建日期做了分区表,索引全部为普通索引未做分区索引。 优化建议: 1、将UNIQUE改为HASH(64) GLOBAL IND…

[区块链lab2] 构建具备加密功能的Web服务端

实验目标&#xff1a; 掌握区块链中密码技术的工作原理。在基于Flask框架的服务端中实现哈希算法的加密功能。 实验内容&#xff1a; 构建Flash Web服务器&#xff0c;实现哈希算法、非对称加密算法的加密功能。 实验步骤&#xff1a; 哈希算法的应用&#xff1a;创建hash…

muduo库源码分析: TcpConnection

一. 主要成员: socket_&#xff1a;用于保存已连接套接字文件描述符。channel_&#xff1a;封装了上面的socket_及其各类事件的处理函数&#xff08;读、写、错误、关闭等事件处理函数&#xff09;。这个Channel中保存的各类事件的处理函数是在TcpConnection对象构造函数中注册…

RuoYi-Vue升级为https访问-后端安装SSL证书(单台Linux服务器部署)

一、前言 当Nginx已经作为反向代理并成功配置了SSL证书时,前端客户端与Nginx的通信已经是加密的。但Nginx和后端服务之间的连接可能仍然存在明文传输的风险。 如果Nginx和后端服务位于同一台物理机器或者通过安全的内部网络(如私有VLAN或防火墙保护的内网)进行通信,则可以…

博客文章文件名该怎么取?

文章目录 &#x1f9fe; 1. 博客文章文件名该怎么取&#xff1f;&#x1f4cc; 2. 为什么文件名重要&#xff1f;✅ 3. 推荐命名规范✅ 3.1 使用 **小写英文 中划线&#xff08;kebab-case&#xff09;**✅ 3.2 简短但具备语义✅ 3.3 如果是系列文章&#xff0c;可加前缀序号或…

【Web API系列】Web Shared Storage API之WorkletSharedStorage深度解析与实践指南

前言 在现代Web开发领域&#xff0c;数据存储与隐私保护的矛盾始终存在。传统存储方案如LocalStorage和Cookies面临着日益严格的安全限制&#xff0c;而跨域数据共享的需求却在持续增长。正是在这样的背景下&#xff0c;Web Shared Storage API应运而生&#xff0c;其核心组件…