缓存最佳实践
目录
前言
一、Cache Aside(旁路缓存)策略
二、不一致解决场景及解决方案
一、数据库主从不一致
二、缓存与数据库不一致
三、问题分析
三、缓存误用
一、多服务共用缓存实例
二、调用方缓存数据
三、缓存作为服务与服务之间传递数据的媒介
四、使用缓存未考虑雪崩
总结
前言
缓存,是互联网分层架构中,非常重要的一个部分,通常用它来降低数据库压力,提升系统整体性能,缩短访问时间。有架构师说“缓存是万金油,哪里有问题,加个缓存,就能优化”,缓存的滥用,可能会导致一些错误用法。
缓存,你真的用对了么?
一、Cache Aside(旁路缓存)策略
旁路缓存策略是最常用的一种缓存读写策略,它适用于读请求比较多,数据更新频率不高的场景。它的基本思想是:应用程序直接访问缓存和数据库,而不通过中间层。当需要读取数据时,先从缓存中查找,如果命中则直接返回;如果未命中,则从数据库中查询,并将结果放入缓存中,然后返回。当需要更新数据时,先更新数据库,然后删除缓存。
Cache Aside 策略(也叫旁路缓存策略),这 个策略数据以数据库中的数据为准,缓存中的数据是按需加载的。它可以分为读策略和写策 略。
其中读策略的步骤是:
- 从缓存中读取数据,如果缓存命中,则直接返回数据;
- 如果缓存不命中,则从数据库中查询数据;
- 查询到数据后,将数据写入到缓存中,并且返回给用户。
- 更新数据库中的记录;
- 删除缓存记录。
不过这种问题出现的几率并不高,原因是缓存的写入通常远远快于数据库的写入,所以在实际中很难出现请求 B 已经更新了数据库并且清空了缓存,请求 A 才更新完缓存的情况。而一旦请求 A 早于请求 B 清空缓存之前更新了缓存,那么接下来的请求就会因为缓存为空而从数据库中重新加载数据,所以不会出现这种不一致的情况。
Cache Aside 策略是我们日常开发中最经常使用的缓存策略,不过我们在使用时也要学会依情况而变。比如说当新注册一个用户,按照这个更新策略,你要写数据库,然后清理缓存(当然缓存中没有数据给你清理)。可当我注册用户后立即读取用户信息,并且数据库主从分离时,会出现因为主从延迟所以读不到用户信息的情况。而解决这个问题的办法恰恰是在插入新数据到数据库之后写入缓存,这样后续的读请求就会从缓存中读到数据了。并且因为是新注册的用户,所以不会出现并发更新用户信息的情况。Cache Aside 存在的最大的问题是当写入比较频繁时,缓存中的数据会被频繁地清理,这样会对缓存的命中率有一些影响。
二、不一致解决场景及解决方案
发生写请求后(不管是先操作DB,还是先淘汰Cache),在主从数据库同步完成之前,如果有读请求,都可能发生读Cache Miss,读从库把旧数据存入缓存的情况。此时怎么办呢?
一、数据库主从不一致
无缓存时,数据库主从不一致问题
如上图,发生的场景是,写后立刻读:
(1)主库一个写请求(主从没同步完成)
(2)从库接着一个读请求,读到了旧数据
(3)最后,主从同步完成
导致的结果是:主动同步完成之前,会读取到旧数据。可以看到,主从不一致的影响时间很短,在主从同步完成后,就会读到新数据。
二、缓存与数据库不一致
再看,引入缓存后,缓存和数据库不一致问题。
如上图,发生的场景也是,写后立刻读
导致的结果是:旧数据放入缓存,即使主从同步完成,后续仍然会从缓存一直读取到旧数据。
可以看到,加入缓存后,导致的不一致影响时间会很长,并且最终也不会达到一致。
三、问题分析
可以看到,这里提到的缓存与数据库数据不一致,根本上是由数据库主从不一致引起的。当主库上发生写操作之后,从库binlog同步的时间间隔内,读请求,可能导致有旧数据入缓存。
思路:那能不能写操作记录下来,在主从时延的时间段内,读取修改过的数据的话,强制读主,并且更新缓存,这样子缓存内的数据就是最新。在主从时延过后,这部分数据继续读从库,从而继续利用从库提高读取能力。
选择性读主
可以利用一个缓存记录必须读主的数据。
如上图,当写请求发生时:
(1)写主库
(2)将哪个库,哪个表,哪个主键三个信息拼装一个key设置到cache里,这条记录的超时时间,设置为“主从同步时延”
PS:key的格式为“db:table:PK”,假设主从延时为1s,这个key的cache超时时间也为1s。
如上图,当读请求发生时:
这是要读哪个库,哪个表,哪个主键的数据呢,也将这三个信息拼装一个key,到cache里去查询,如果,
(1)cache里有这个key,说明1s内刚发生过写请求,数据库主从同步可能还没有完成,此时就应该去主库查询。并且把主库的数据set到缓存中,防止下一次cahce miss。
(2)cache里没有这个key,说明最近没有发生过写请求,此时就可以去从库查询
以此,保证读到的一定不是不一致的脏数据。
PS:如果系统可以接收短时间的不一致,建议定时更新缓存就可以了。避免系统过于复杂。
三、缓存误用
一、多服务共用缓存实例
如上图:服务A和服务B共用一个缓存实例(不是通过这个缓存实例交互数据)
该方案存在的问题是:
1、可能导致key冲突,彼此冲掉对方的数据
可能需要服务A和服务B提前约定好了key,以确保不冲突,常见的约定方式是使用namespace:key的方式来做key。
2、不同服务对应的数据量,吞吐量不一样,共用一个实例容易导致一个服务把另一个服务的热数据挤出去
3、共用一个实例,会导致服务之间的耦合,与微服务架构的“数据库,缓存私有”的设计原则是相悖的
正确的部署方式是
如上图:各个服务私有化自己的数据存储,对上游屏蔽底层的复杂性。
二、调用方缓存数据
如上图,服务提供方缓存,向调用方屏蔽数据获取的复杂性。服务调用方,也缓存一份数据,先读自己的缓存,再决定是否调用服务(这个有问题)
该方案存在的问题是:
1、调用方需要关注数据获取的复杂性(耦合问题)
2、更严重的,服务修改db里的数据,淘汰了服务cache之后,难以通知调用方淘汰其cache里的数据,从而导致数据不一致(带入一致性问题)
3、有人说,服务可以通过MQ通知调用方淘汰数据,额,难道下游的服务要依赖上游的调用方,分层架构设计不是这么玩的(反向依赖问题)
三、缓存作为服务与服务之间传递数据的媒介
如上图:服务A和服务B约定好key和value,通过缓存传递数据服务A将数据写入缓存,服务B从缓存读取数据,达到两个服务通信的目的
多个服务关联同一个缓存实例,会导致服务耦合
(1)大家要彼此协同约定key的格式,ip地址等,耦合
(2)约定好同一个key,可能会产生数据覆盖,导致数据不一致
(3)不同服务业务模式,数据量,并发量不一样,会因为一个cache相互影响,例如service-A数据量大,占用了cache的绝大部分内存,会导致service-B的热数据全部被挤出cache,导致cache失效;又例如service-A并发量高,占用了cache的绝大部分连接,会导致service-B拿不到cache的连接,从而服务异常
四、使用缓存未考虑雪崩
常规的缓存玩法,如上图:
服务先读缓存,缓存命中则返回;缓存不命中,再读数据库
什么时候会产生雪崩?
如果缓存挂掉,所有的请求会压到数据库,如果未提前做容量预估,可能会把数据库压垮(在缓存恢复之前,数据库可能一直都起不来),导致系统整体不可服务。
如何应对潜在的雪崩?
提前做容量预估,如果缓存挂掉,数据库仍能扛住,才能执行上述方案。
否则,就要进一步设计。
常见方案一:高可用缓存
如上图:使用高可用缓存集群,一个缓存实例挂掉后,能够自动做故障转移。
常见方案二:缓存水平切分
如上图:使用缓存水平切分(推荐使用一致性哈希算法进行切分),一个缓存实例挂掉后,不至于所有的流量都压到数据库上。
总结
1、服务与服务之间不要通过缓存传递数据
2、如果缓存挂掉,可能导致雪崩,此时要做高可用缓存,或者水平切分
3、调用方不宜再单独使用缓存存储服务底层的数据,容易出现数据不一致,以及反向依赖
4、不同服务,缓存实例要做垂直拆分。
相关文章:

缓存最佳实践
目录 前言 一、Cache Aside(旁路缓存)策略 二、不一致解决场景及解决方案 一、数据库主从不一致 二、缓存与数据库不一致 三、问题分析 三、缓存误用 一、多服务共用缓存实例 二、调用方缓存数据 三、缓存作为服务与服务之间传递数据的媒介 四…...

Linux 终端命令之文件目录操作,对比Dos相关命令
目录 前言 基础命令(文件目录相关的) cd命令 【英文帮助】 【对应Dos命令】 pwd命令 【英文帮助】 【对应Dos命令】 ls命令 【英文帮助】 【对应Dos命令】 tree命令 【英文帮助】 【对应Dos命令】 mkdir命令 【英文帮助】 【对应Dos命令…...
C++学习第十八天----switch语句
1. ?:运算符 条件运算符,又叫三元运算符; 该运算符的通用格式为: expression1?expression2 :expression3; 意义是假如1为true,则整个条件表达式的值为2的值,否则为3的值&…...
基于poi生成excel模板并生成下拉选择框
直接上代码(有注释) public void downloadImportTemplate(HttpServletResponse response) {try {ServletOutputStream outputStream response.getOutputStream();//创建工作表XSSFWorkbook workbook new XSSFWorkbook();//标题行的标题List<String…...

Redis五种类型
Redis 基础类型 String 应用场景 缓存功能:string 最常用的就是缓存功能,会将一些更新不频繁但是查询频繁的数据缓存起来,以此来减轻 DB 的压力。 底层实现 如果字符串对象保存的是一个字符串值, 并且这个字符串值的长度大于…...

通过IP地址如何防范钓鱼网站诈骗?
随着互联网的普及和发展,钓鱼网站诈骗的风险日益增加。钓鱼网站通过伪装成合法网站,诱导用户输入个人敏感信息进而进行非法活动。IP地址作为网络通信的基本单位,可以在一定程度上帮助我们防范钓鱼网站诈骗。本文将探讨IP地址防范钓鱼网站诈骗…...
useEffect使用详解
useEffect是React中的一个钩子函数,用于处理副作用操作。副作用是指在组件渲染过程中,可能会对外部环境产生影响的操作,比如数据获取、订阅事件、操作DOM等。 useEffect接受两个参数:一个是副作用函数,另一个是依赖数…...

element-table的动态操作,自动以表格,动态新增行、列,删除行列
灵活的自定义表格行列以及增删改查的操作,右键选中列则是列的删除,效果如下 <template><div class"st-table"><div style"width: 100%"><el-button click"addRow()" type"primary" icon"CircleP…...

python--文件管理系统
文件系统管理项目说明文档 项目说明 基本任务 在内存中开辟一个空间作为文件存储器,在其上实现一个简单的文件系统退出这个文件系统时,需要该文件系统的内容保存到磁盘上,以便下次可以将其回复到内存中来 具体要求 文件存储空间管理可采取链…...

uniapp 微信小程序:RecorderManager 录音DEMO
uniapp 微信小程序:RecorderManager 录音DEMO 简介index.vue参考资料 简介 使用 RecorderManager 实现录音。及相关的基本操作。(获取文件信息,上传文件) 此图包含Demo中用于上传测试的服务端程序upload.exe,下载后用…...
__call__和__init__和__new__和__str__和__repr__
目录 一、__call__ 二、__init__和__new__ 三、__str__ 四、__repr__ python从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129328397?spm1001.2014.3001.5502 一、__call__ 对象后面加括号时,触发执行。注:构…...

设计模式--工厂模式(Factory Pattern)
一、 什么是工厂模式 工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的接口,但是将对象的实例化过程推迟到子类中。工厂模式允许通过调用一个共同的接口方法来创建不同类型的对象,而无需暴露对…...

【Android】 No matching variant of com.android.tools.build:gradle:[版本号] was found
项目报错 No matching variant of com.android.tools.build:gradle:8.1.1 was found. The consumer was configured to find a library for use during runtime, compatible with Java 8, packaged as a jar, and its dependencies declared externally, as well as attribute …...

650V 1200V碳化硅二极管MOS管规格书参数,6A 8A 10A 15A 20A 封装TO220低VF电压 低内阻特性
650V碳化硅二极管6A 8A 15A提供样品 650V 40毫欧超结COOL MOS提供样品 650V 超结COOL MOS资料 国产替代 650V 1200V碳化硅二极管技术资料...

python基础—python6种基本数据类型及数据类型之间转换
文章目录 一、python标准数据类型(一)数字类型整型:int浮点型:flaot布尔型:bool复数类型:complex (二)字符串(三)列表类型(四)元组类型…...

Axure RP
Axure RP 简介下载安装汉化注册 简介 Axure RP(Rapid Prototyping)是一款交互式原型设计工具,用于创建高保真的交互式界面原型和线框图。它主要用于用户体验(UX)和用户界面(UI)设计,…...
java使用ExcelExportUtil.exportBigExcel导出大文件(非分页)
网上看到很多使用这个方法处理的时候,大多使用的分页进行查询,但是当遇到特殊的产品需求,比如A类型数据,多条记录就显示多行,B类型的要求存在多条记录时,就进行汇总后只显示一条,这就导致无法使…...

PlantUML文本绘制类图
记录下文本绘制类图的语法 参考 https://juejin.cn/post/6844903731293585421 类的UML表示 使用UML表示一个类,主要由三部分组成。类名、属性、方法。其中属性和方法的访问修饰符用 - 、# 、 表示 private、protected、public。 如图所示,表示A类有一个…...
5分钟理解NPL算法 之 马尔可夫链 Markov Chain
马尔可夫链(Markov Chain) 马尔可夫链是一种简单的推理模型。用于描述受当前事件影响下的下一事件发生概率。在预测学科中广泛应用。例如股票预测、文字推理、路线推荐等。 他的核心思路是:假设事件顺序为: X 1 , X 2 , X 3 , . . . . . X…...

C#_GDI+ 绘图编程入门
官网提供相关API GDI 基本图形功能_drawing 高级二维和矢量图形功能_drawing2D GDI 图像处理功能_Imaging GDI 排版功能_text Windows 窗体应用程序提供打印功能_Printing 像素 构成图像的最小单位就是像素;屏幕上显示不管是位图或者矢量图,当描述…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...