缓存策略通用分布式缓存解决方案

Cache Aside(旁路缓存)策略

Cache Aside(旁路缓存)策略是一种在应用程序中协调缓存与数据库交互的常用策略,是使用最多的策略。

基本原理

  • 读操作:应用程序首先尝试从缓存中读取数据,如果缓存命中,则直接返回该数据。如果缓存未命中,应用程序会从数据库中查询读取数据,读取数据后,写入缓存并返回数据。
  • 更新(写)操作:当数据需要更新时,应用程序先更新数据库中的数据,更新成功后,再删除缓存中的数据。之所以删除缓存而不是更新缓存,是因为更新操作可能只修改了部分字段,如果直接更新缓存,可能导致缓存数据与数据库数据的不一致,而删除缓存可以保证下次读取时从数据库获取最新的数据并重新写到缓存

更新(写)策略的顺序不能颠倒,因为缓存操作要远远快于数据库操作,所以很难出现以下并发情况:第一个请求读取缓存发现未命中,又读取数据库。第二个请求更新数据库并删除了缓存。第一个请求才将数据库的内容写入缓存。

适用场景

读多写少。因为写频繁时,缓存中的数据会被频繁的清理,这样会对缓存的命中有影响。如果业务对于缓存命中率有严格要求,那么可以考虑以下两种方案:

  • 更新数据库后,在更新缓存时,先加一个分布式锁,这样同一时刻只允许一个线程修改缓存。这样做会对于写的性能有一定影响
  • 更新数据库后,给缓存加一个较短的过期时间,这样虽然较短时间内数据有不一致情况,但缓存数据很快就会过期,对业务的影响也是接受的

通用分布式缓存解决方案

分布式缓存问题:

  • 直接将数据直接存入Redis,如果数据是对象,从缓存中获取时,反序列化效率低;而且数据量大时,造成缓存会占用较大空间
  • 将数据做本地缓存,数据更新时,要考虑在集群环境下,本地数据和数据库的一致性

Redis缓存标志位U0,每次数据修改同步修改U0。本地缓存标志位U1,从缓存取数据时,先判断Redis缓存标志位U0和本地标志位U1是否相等,相等代表是最新的数据,可以直接从本地缓存中取。否则就查数据库,更新本地缓存。

public class CacheUtil {private static Map<String, Object[]> cache;private static StringRedisTemplate stringRedisTemplate;private static volatile CacheUtil cacheUtil = null;public static CacheUtil getInstance() {if (cacheUtil == null) {synchronized (CacheUtil.class) {if (cacheUtil == null) {cacheUtil = new CacheUtil();cacheUtil.init();}}}return cacheUtil;}private CacheUtil() {}private void init() {cache = new ConcurrentHashMap<>();stringRedisTemplate = ApplicationContextRegister.getBean(StringRedisTemplate.class);}public <T> T getAndSetCacheObject(Supplier<T> supplier, String key) {if (!StringUtils.hasText(key)) {return null;}T result;// 获取redis中的标记String redisFlag = stringRedisTemplate.boundValueOps(key).get();// 未获取到,查数据库,做本地缓存,向redis和本地存入标记if (redisFlag == null) {result = supplier.get();if (result != null) {setCacheObject(key, result);}} else {Object[] localCache = cache.get(key);//本地缓存为空,查数据库,做本地缓存,并存入标记if (localCache == null) {result = supplier.get();if (result != null) {Object[] cacheInfo = {redisFlag, result};cache.put(key, cacheInfo);}} else {String localFlag = (String) localCache[0];// 本地标记与redis中的标记相同,直接从本地获取if (Objects.equals(redisFlag, localFlag)) {result = (T) localCache[1];} else {// 否则,查数据,更新本地缓存和标记result = supplier.get();if (result != null) {Object[] cacheInfo = {redisFlag, result};cache.put(key, cacheInfo);}}}}return result;}private void setCacheObject(String key, Object data) {String uuid = UUID.randomUUID().toString();Object[] cacheInfo = {uuid, data};cache.put(key, cacheInfo);stringRedisTemplate.boundValueOps(key).set(uuid);}public void refreshCache(String key) {if (!StringUtils.hasText(key)) {return;}stringRedisTemplate.boundValueOps(key).set(UUID.randomUUID().toString());}
}

使用

@Service
public class StudentServiceImpl implements StudentService {@Autowiredprivate StudentDao dao;@Autowiredprivate StudentService studentService;@Overridepublic Student getStudent(String id) {return CacheUtil.getInstance().getAndSetCacheObject(new Supplier<Student>() {@Overridepublic Student get() {Student student = new Student();student.setId(id);return dao.selectOne(student);}}, "student:" + id);}@Overridepublic void update(Student student) {// 这里注入studentService自身调用更新方法(不做详细讲解,知道的小伙伴可评论补充)// 双更新尽最大可能减少数据不一致问题(不做详细讲解,知道的小伙伴可评论补充)studentService.updateStudent(student);// 事务外更新CacheUtil.getInstance().refreshCache("student:" + student.getId());}@Override@Transactional(rollbackFor = Exception.class)public void updateStudent(Student student) {// ...一系列校验// ...其他操作// 更新dao.update(student);// 事务内更新CacheUtil.getInstance().refreshCache("student:" + student.getId());}}

Read/Write Through(读穿 / 写穿)策略

Read/Write Through(读穿 / 写穿)策略最大的特点是,应用程序不直接与数据库交互,而是应用程序只与缓存交互,缓存与数据库交互。相当于缓存在中间做了代理。

基本原理

  • 读穿(Read Through):当应用程序请求数据时,他并不直接与数据库交互,而是向缓存请求数据,如果缓存中有需要的数据(缓存命中),则直接返回给应用程序;如缓存未命中,缓存系统自动查询数据库获取数据,将其放入缓存,然后返回给应用程序。
  • 写穿(Write Through):当应用程序要更新数据时,也是将数据发送给缓存,缓存收到数据后,先判断缓存中是否存在该数据,若存在,会将数据写入数据库,同时更新缓存中的数据,确保缓存中的数据与数据库中的数据相同。若不存在,则直接更新数据库。

Read Through/Write Through 策略的特点是由缓存节点而非应用程序来和数据库打交道,在我们开发过程中相比 Cache Aside 策略要少见一些,原因是我们经常使用的分布式缓存组件,无论是 Memcached 还是 Redis 都不提供写入数据库和自动加载数据库中的数据的功能。而我们在使用本地缓存的时候可以考虑使用这种策略。

Write Back(写回)策略

  • Write Back(写回策略)的特点:在数据更新的时候,只会更新缓存中的数据,然后将该数据标记为 “脏” 的或 “已修改” 的状态,并不会更新数据库中的数据,而是在合适的时机或满足特定的条件下,将特定状态的缓存数据以特定的方式 “刷” 到数据源,从而达到数据的最终一致性。写回策略适合用于写多,并且读取数据实时性不高的场景,写回策略在操作系统的文件系统、CPU缓存都采用了写回策略。例如:在编辑World或其他文档时,如果未保存,发生了断电,就会造成原本缓存中的脏数据丢失,之前编辑的内容会丢失一部分,就是因为缓存数据还未刷新到磁盘导致的。

  • 写回时机:基于时间的写回:固定时间间隔、基于空间的写回:达到缓存空间使用阈值、基于事件的写回:程序主动调用特定方法。

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

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

相关文章

本地大模型编程实战(03)语义检索(2)

文章目录 准备按批次嵌入加载csv文件&#xff0c;分割文档并嵌入测试嵌入效果总结代码 上一篇文章&#xff1a; 本地大模型编程实战(02)语义检索(1) 详细介绍了如何使用 langchain 实现语义检索&#xff0c;为了演示方便&#xff0c;使用的是 langchain 提供的内存数据库。 在实…

sql中INNER JOIN、LEFT JOIN、RIGHT JOIN

INNER JOIN 的作用 INNER JOIN 只会将相关联表匹配到的数据进行展示 假设我们有两个表&#xff1a;sys_user和 sys_user_role SELECT s1.* from sys_user s1 INNER JOIN sys_user_role s2 on s1.id s2.user_id 这样只会展示s1.id s2.user_id相匹配到的数据&#xff0c;其他数…

Vue 3 中的 toRef 与 toRefs:使用与案例解析

在 Vue 3 的响应式系统中&#xff0c;toRef 和 toRefs 是两个非常实用的工具函数。它们主要用于将响应式对象的属性转换为单独的 ref&#xff0c;以便在模板或逻辑中更方便地使用。本文将详细介绍 toRef 和 toRefs 的用法&#xff0c;并通过一个老师信息的案例来演示它们的实际…

以太网详解(六)OSI 七层模型

文章目录 OSI : Open System Interconnect&#xff08;Reference Model&#xff09;第七层&#xff1a;应用层&#xff08;Application&#xff09;第六层&#xff1a;表示层&#xff08;Presentation&#xff09;第五层&#xff1a;会话层&#xff08;Session&#xff09;第四…

单片机基础模块学习——DS18B20温度传感器芯片

不知道该往哪走的时候&#xff0c;就往前走。 一、DS18B20芯片原理图 该芯片共有三个引脚&#xff0c;分别为 GND——接地引脚DQ——数据通信引脚VDD——正电源 数据通信用到的是1-Wier协议 优点&#xff1a;占用端口少&#xff0c;电路设计方便 同时该协议要求通过上拉电阻…

在每一次灵感碰撞中,见证成长的蜕变--24年年度总结

我也来写一个年度总结吧。从24年8月5号开始了职业生涯的第一篇创作&#xff0c;当时刚好被拉去封闭开发了&#xff0c;做一个保密的AI赋能业务的项目。当时写博客的初衷是为了记录项目中遇到的一些问题以及技术栈的使用、原理剖析等&#xff0c;从而让自己快速成长。没想到文章…

基于paddleocr的表单关键信息抽取

全流程如下&#xff1a; 数据集 XFUND数据集是微软提出的一个用于KIE任务的多语言数据集&#xff0c;共包含七个数据集&#xff0c;每个数据集包含149张训练集和50张验证集分别为&#xff1a; ZH(中文)、JA(日语)、ES(西班牙)、FR(法语)、IT(意大利)、DE(德语)、PT(葡萄牙)&a…

AIGC视频扩散模型新星:Video 版本的SD模型

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍慕尼黑大学携手 NVIDIA 等共同推出视频生成模型 Video LDMs。NVIDIA 在 AI 领域的卓越成就家喻户晓&#xff0c;而慕尼黑大学同样不容小觑&#xff0c;…

深度解析:基于Vue 3的教育管理系统架构设计与优化实践

一、项目架构分析 1. 技术栈全景 项目采用 Vue 3 TypeScript Tailwind CSS 技术组合&#xff0c;体现了现代前端开发的三大趋势&#xff1a; 响应式编程&#xff1a;通过Vue 3的Composition API实现细粒度响应 类型安全&#xff1a;约60%的组件采用TypeScript编写 原子化…

运用python进行多任务学习过程中,手动调整权重时,如何选择项目并确定合适的权重值?

在手动调整多任务学习中不同任务的损失权重时,确定合适的权重值是一个需要细致考虑的问题。以下是一些基于最新研究和实践的方法和策略: 第一部分:手动调整权重确定合适的权重值 1. 基于任务的重要性 方法:根据任务的重要性手动分配权重。例如,如果一个任务对最终性能的影…

aws(学习笔记第二十六课) 使用AWS Elastic Beanstalk

aws(学习笔记第二十六课) 使用aws Elastic Beanstalk 学习内容&#xff1a; AWS Elastic Beanstalk整体架构AWS Elastic Beanstalk的hands onAWS Elastic Beanstalk部署node.js程序包练习使用AWS Elastic Beanstalk的ebcli 1. AWS Elastic Beanstalk整体架构 官方的guide AWS…

视频多模态模型——视频版ViT

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细解读多模态论文《ViViT: A Video Vision Transformer》&#xff0c;2021由google 提出用于视频处理的视觉 Transformer 模型&#xff0c;在视频多模态领域有…

【ArcGIS微课1000例】0141:提取多波段影像中的单个波段

文章目录 一、波段提取函数二、加载单波段导出问题描述:如下图所示,img格式的时序NDVI数据有24个波段。现在需要提取某一个波段,该怎样操作? 一、波段提取函数 首先加载多波段数据。点击【窗口】→【影像分析】。 选择需要处理的多波段影像,点击下方的【添加函数】。 在多…

讨论:延迟双删,要延迟多久呢?

这个延迟双删&#xff0c;其实是保证数据库和缓存数据一致性的一种方案来的。大家觉得应该如何回答更好呢&#xff1f;我觉得可以先从最基础的开始聊起&#xff0c;比如什么是一致性&#xff0c;然后从串联起来。我聊聊我的思路。 首先&#xff0c;先回归基础&#xff0c;什么…

SQL Server查询计划操作符(7.3)——查询计划相关操作符(5)

7.3. 查询计划相关操作符 38)Flow Distinct:该操作符扫描其输入并对其去重。该操作符从其输入得到每行数据时即将其返回(除非其为重复数据行,此时,该数据行会被抛弃),而Distinct操作符在产生任何输出前将消费所有输入。该操作符为逻辑操作符。该操作符具体如图7.2-38中…

智慧消防营区一体化安全管控 2024 年度深度剖析与展望

在 2024 年&#xff0c;智慧消防营区一体化安全管控领域取得了令人瞩目的进展&#xff0c;成为保障营区安全稳定运行的关键力量。这一年&#xff0c;行业在政策驱动、技术创新应用、实践成果及合作交流等方面呈现出多元且深刻的发展态势&#xff0c;同时也面临着一系列亟待解决…

关于圆周率的新认知

从自然对数底 的泰勒展开&#xff0c; 可以得出 的展开式&#xff0c; 它可以被认为是&#xff0c;以 0 为周期的单位 1 &#xff0c;以 1 为周期的单位 1 &#xff0c;以 2 为周期的单位 1 等所有自然数为周期的单位 1 分阶段合成&#xff08;体现为阶乘的倒数&#xff09;之…

Flutter使用Flavor实现切换环境和多渠道打包

在Android开发中通常我们使用flavor进行多渠道打包&#xff0c;flutter开发中同样有这种方式&#xff0c;不过需要在原生中配置 具体方案其实flutter官网个了相关示例&#xff08;https://docs.flutter.dev/deployment/flavors&#xff09;,我这里记录一下自己的操作 Android …

通过亚马逊云科技Bedrock打造自定义AI智能体Agent(上)

大家对于智能体代理Agent一定已经非常熟悉&#xff0c;自主代理&#xff08;Autonomous Agents&#xff09; 目前在AI行业极其热门并具有巨大的潜力&#xff0c;能够显著提升开发者日常的工作效率、自动化日常琐碎、重复性任务&#xff0c;并生成全新的内容。Agent可以理解用户…

基于STM32的阿里云智能农业大棚

目录 前言&#xff1a; 项目效果演示&#xff1a; 一、简介 二、硬件需求准备 三、硬件框图 四、CubeMX配置 4.1、按键、蜂鸣器GPIO口配置 4.2、ADC输入配置 4.3、IIC——驱动OLED 4.4、DHT11温湿度读取 4.5、PWM配置——光照灯、水泵、风扇 4.6、串口——esp8266模…