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

Redis 数据一致性方案的分析与研究

点击下方关注我,然后右上角点击...“设为星标”,就能第一时间收到更新推送啦~~~

一般的业务场景都是读多写少的,当客户端的请求太多,对数据库的压力越来越大,引入缓存来降低数据库的压力是必然选择,目前业内主流的选择基本是使用 Redis 作为数据库的缓存。但是引入缓存以后,对我们系统的设计带来了很大的挑战,其中缓存和数据库的数据一致性问题就是一个非常棘手的问题,今天我们就来聊一聊在项目中,我们用什么方案来解决数据一致性的问题。

1

Redis 的使用场景

bbceb65e690e776cda4de5b52d6d0f31.png

我们在实际项目中,通常情况下的应用是读多写少的,我们一般用 Redis 来解决读数据库的压力问题,也就是说用 Redis 作为缓存来减轻由于客户端频繁查询数据库而对数据库造成的压力。

因此在项目中由客户端直接查询数据库返回数据,变成了客户端查询 Redis 缓存,缓存有数据则直接返回数据,缓存没有数据再去查询数据库,同时数据库的数据写入到 Redis 缓存。

e455a1d6f394b4ca67416239a94db6dc.png

在以上的使用场景中,我们一般缓存热点数据,比如电商平台中的热销商品,用户的登录信息,新闻类平台中的热点新闻等。

2

数据一致性问题产生的原因

be3866656da2c9c3d728e190c26f3f5e.png

当数据库的数据发生变化的时候,引入 Redis 缓存以后,增加了数据操作难度,既要操作数据库又要操作 Redis,对  Redis和数据库的操作有 2 种方案:

1、先操作 Redis,再操作数据库

2、先操作数据库,再操作 Redis

我们无论选择以上的哪个方案,都希望数据操作要么都成功,要么都失败,我们不希望看到一个失败,一个成功的结果,因为这样就产生了数据不一致的问题。

举个例子说明:

假设 Redis 里缓存了一个热点商品数据,有个 key 为 1001 的商品名称为“华为手机”,数据库里这个 1001 号的商品名称也是华为手机;此时商家觉得商品名称叫华为手机有点宽泛,需要精确一下,把 1001 号商品的名称修改为其对应的具体名称“华为 P40 Pro”。

1、如果我们选择先操作 Redis,再操作数据库的方案,当操作 Redis 成功,操作数据库失败的时候,Redis 里的名称修改为“华为 P40 Pro”,但是数据库的名称还是“华为手机”,产生了数据不一致问题。

2、如果我们选择先操作数据库,再操作 Redis 的方案,当操作数据库成功,操作 Redis 失败的时候,数据库里的名称修改为“华为 P40 Pro”,但是 Redis 的名称还是“华为手机”,产生了数据不一致问题。

由于 Redis 和数据库是 2 个不同的中间件,我们无法通过事务来很好地解决数据一致性的问题,因此只能在数据实时一致性和系统性能上做权衡,选择一个可以接收的方案。

因为数据库是稳定的持久化的系统,比 Redis可靠,我们一般都是以数据库的数据为准,解决这个数据一致性问题的原则就是:我们可以为 Redis 缓存数据设置一个过期的时间,当 Redis 数据过期了就去数据库查询,然后再把数据库的数据写入 Redis 缓存中,确保数据的一致性。

如果在这个过期时间范围内,数据发生了更新操作,当更新操作有一个失败,有一个成功,就会产生不一致的问题,这个过期时间设置的太短了,数据库的压力还是很大,过期时间设置的太长了,不一致性的问题就会凸显,因此我们需要基于以数据库的数据为准的原则下,继续探讨数据一致性问题的解决方案。

3

数据更新时,如何操作 Redis

60417e1c8e4db6dba7bd27a45f422138.png

当数据更新时,操作数据库我们都很熟悉,直接更新数据库的值就可以了,但是操作 Redis,我们应该怎么办?

1、有人会说,这还不简单,数据变化时,直接更新缓存

2、也有人会说数据变化时把缓存的数据删掉,当查询请求发现缓存没有数据,就会从数据库加载新的数据。

以上的两种方法都可以,那我们该如何选择呢?

如果我们选择更新 Redis 的方案,我们要评估一下更新的代价大不大,比如拿到数据更新到 Redis 需要经过很多表的关联查询,或者多个接口的调用查询,经过大量计算才能得到数据的话,就不要使用更新 Redis 的方案了,因为面对这么复杂的更新流程,不如直接删掉方便。如果要更新的数据直接可以获取到,那么选择更新 Redis 的方案就是可行的。

直接删除 Redis 缓存数据是更加简单的方案,因为缓存数据删了,只能从数据库读取了,这样可以避免不一致性,互联网公司一般选择删除 Redis 的方案。

下面我们用一张图来表示可选的方案:

33dad3e37ef2cb586358a196ac9e2f35.png

通过上图,我们可以看出当数据发生变化时,Redis 与数据库的处理流程我们可以从 Redis更新还是删除这 2 个方面分析,然后再从先操作 Redis还是先操作数据库这 2 个方面分析,下面我们按此思路继续深入分析。

4

选择 Redis 更新方案

c22ccceea50c3deec728e9147925e2f7.png

1、先更新 Redis,再更新数据库

首先不推荐选择这种方案。

因为我们的数据一致性的基本原则是以数据库的数据为准,所以先更新缓存的话,会存在缓存更新成功,数据库更新失败的情况,此时面临的问题就需要回滚掉刚才更新缓存成功的操作,那么就需要从业务代码里加入很多判断逻辑来处理这种异常,需要考虑数据变化是 insert,update,delete 等,根据不同的场景执行不同的回滚方案,这种回滚操作比较麻烦,对我们业务代码的倾入性也比较大,所以不推荐选择这种方案。

当然,如果业务层面可以接受这种数据的不一致性,异常情况就不需要考虑,选择这种方案也是可以的。

2、先更新数据库,再更新 Redis

先更新数据库,再更新 Redis 的方案,由于把数据库操作放到了前面,如果数据库操作失败,那么客户端再发起一次就可以了。

如果数据库操作成功,Redis 操作失败,此时由于数据库的数据已经设置成功,我们的重点就是讨论如何把 Redis的数据操作成功即可。从客户端层面来看,他提交的数据已经在我们系统里存在了,此时的问题就是我们系统内部如何解决的问题。

对于 Redis 操作失败,我们可选的方案有以下几个,根据业务要求的数据一致性级别,进行权衡选择即可。

1、不做任何操作,等着Redis里的缓存数据过期后,自动从数据库同步最新的数据,此时最严重的数据不一致性周期就是在缓存过期的一段时间(考虑一下这个过期时间的范围);如果在这个时间段内,又有新的更新请求,也许这次就更新缓存成功了。

2、如果数据一致性要求比较高,那么 Redis 操作失败后,我们把这个操作记录下来,异步处理,用 Redis 的数据去和数据库比对,如果不一致,再次更新缓存确保缓存数据与数据库数据一致。

5

选择 Redis 删除方案

32e69376e2e67251301a76591863cec7.png

由于目前数据发生变化,主流的方案是选择删除 Redis,所以我们对这个方案重点进行分析。

1、先更新数据库,再删除 Redis

我们如果更新数据库成功,删除 Redis 失败,那么 Redis 里存放的就是一个旧值,也就是删除缓存失败导致缓存和数据库的数据不一致了。

对于删除 Redis 失败的异常情况来进行分析,我们一般有如下的方案:

1、我们可以重试删除,比如:我们可以把删除动作发送到消息队列 MQ,MQ的消费者再去删除这个key,一致尝试删除操作,确保缓存删除成功,这个方案缺陷就是删除缓存的地方,通过代码实现对业务逻辑产生了入侵。

2、另外一种方案,就是完全异步的方案,对业务逻辑没有入侵,通过监听 binlog 的变化来删除缓存。我们更新数据库会产生 binlog,我们可以用一个服务监听数据库 binlog 的变化,异步去删除缓存,阿里开源的 canal 就是可以监听 binlog 的工具,只要数据发生变化就可以删除 Redis 的数据。

2、先删除 Redis,再更新数据库

我们如果删除 Redis 缓存成功,更新数据库失败的话,因为我们是以数据库为准,再查一次就可以了,这个方案看似很理想,感觉没什么问题,其实在并发下也可能产生数据一致性问题。

我们先看一个并发环境下的更新和查询流程:

7027b359d045caa00ec07b8a0831836b.png

上面的图表示,Thread-1 是个更新流程,Thread-2 是个查询流程,cpu 执行顺序是:Thread-1 删除缓存成功,此时 Thread-2 获取到 CPU 执行查询缓存没有数据,然后查询数据库把数据库的值写入缓存,因为此时 Thread-1 更新数据库还没有执行,所以缓存里的值是一个旧值(old),最后 CPU 执行 Thread-1 更新数据库成功的代码,那么此时数据库的值是新增(new),这样就产生了数据不一致行的问题。

要解决以上的问题,我们我们一般有如下的可选方案:

1、并发下多线程操作能不能让同一个操作里的 2 个步骤同时操作完成,下一个线程才能执行,让各个线程排队操作,有人说加锁,如果一个服务部署到了多个机器,就变成了分布式锁,或者是分布式队列按顺序去操作数据库或者 Redis,带来的副作用就是数据库本来是并发的,现在变成串行的了,所以这个方案看起来不太可行,加锁或者排队执行的方案降低了系统性能。

2、另外一种放啊就是延时双删的方案,也就是先删除缓存,再更新数据库,当更新数据后休眠一段时间再删除一次缓存。

伪代码如下:

redes.del(key);
db.update(data);
Thread.sleep(2000);
redes.del(key);

以上谈到的都是一些解决方案,没有说哪个方案更好,或者哪个方案不行,以上的方案都是基于实时一致性和系统性能的情况下进行权衡选择,根据不同的业务,不同的数据一致性要求,结合系统的性能综合考虑,选择适合自己系统的方案就好。

总的来说,由于我们的基本原则是以数据库为准,那么我们选择的方案就应该把操作数据库放到前面,也就是说我们应该先操作数据库,再操作 Redis,对于并发很高的场景,我们可以在操作数据库之前通过消息队列来降低客户端对数据库的请求压力。

相关文章:

Redis 数据一致性方案的分析与研究

点击下方关注我,然后右上角点击...“设为星标”,就能第一时间收到更新推送啦~~~ 一般的业务场景都是读多写少的,当客户端的请求太多,对数据库的压力越来越大,引入缓存来降低数据库的压力是必然选择,目前业内…...

【网络安全】黑客自学笔记

1️⃣前言 🚀作为一个合格的网络安全工程师,应该做到攻守兼备,毕竟知己知彼,才能百战百胜。 计算机各领域的知识水平决定你渗透水平的上限🚀 【1】比如:你编程水平高,那你在代码审计的时候就会比…...

深入解析Perlin Simplex噪声函数:在C++中构建现代、高效、免费的3D图形背景

引言 在计算机图形中,噪声是一个经常被讨论的话题。无论是为了制造自然的纹理,还是为了模拟复杂的现实世界现象,噪声函数都在其中起着关键作用。而在众多噪声函数中,Perlin Simplex 噪声无疑是最受欢迎的一种。其原因不仅在于其干…...

【计算机辅助蛋白质结构分析、分子对接、片段药物设计技术与应用】

第一天 上午 生物分子互作基础 1.生物分子相互作用研究方法 1.1蛋白-小分子、蛋白-蛋白相互作用原理 1.2 分子对接研究生物分子相互作用 1.3 蛋白蛋白对接研究分子相互作用 蛋白数据库 1. PDB 数据库介绍 1.1 PDB蛋白数据库功能 1.2 PDB蛋白数据可获取资源 1.3 PDB蛋白数据库对…...

免费开箱即用微鳄售后工单管理系统

编者按:本文介绍基于天翎MyApps低代码平台开发的微鳄售后工单管理系统, 引入低代码平台可以帮助企业快速搭建和部署售后工单管理系统, 以工作流作为支撑,在线完成各环节数据审批,解决售后 工单 服务的全生命周期过程管…...

vant 组件库的基本使用

文章目录 vant组件库1、什么是组件库2、vant组件 全部导入 和 按需导入的区别3、全部导入的使用步骤:4、按需导入的使用步骤:5、封装vant文件包 vant组件库 该项目将使用到vant-ui组件库,这里的目标就是认识他,铺垫知识 1、什么…...

HTML常用基本元素总结

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title> biao qian</title> </head> <body><h1>这是标题1</h1> <h2>这是标题2</h2> <h3>这是标题3</h3><p> 这…...

msvcp140.dll重新安装的解决方法是什么?(最新方法)

msvcp140.dll 是 Microsoft Visual C Redistributable 的一个动态链接库文件&#xff0c;它包含了 C 运行时库的一些函数和类&#xff0c;对于许多应用程序和游戏来说都是必需的。如果您的系统中缺失了这个文件&#xff0c;可能会导致程序无法正常运行。下面我们将分享修复 msv…...

USI-0002 SDI-1624 HONEYWELL ,用于工业和物流4.0的人工智能

USI-0002 SDI-1624 HONEYWELL &#xff0c;用于工业和物流4.0的人工智能 生产、仓库、运输——生产、储存、分拣或包装货物的地方&#xff0c;也是提货的地方。这意味着几个单独的货物从存储单元如箱子或纸盒中取出并重新组装。有了FLAIROP(机器人采摘的联邦学习)项目费斯托…...

计算机竞赛 深度学习 python opencv 火焰检测识别

文章目录 0 前言1 基于YOLO的火焰检测与识别2 课题背景3 卷积神经网络3.1 卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV54.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 数据集准备5.1 数…...

Intellij idea 2023 年下载、安装教程、亲测可用

文章目录 1 下载与安装IDEA2 常用设置设置 Java JDK 版本自动导入包、移除包IDEA 自动生成 author 注释签名java.io.File 类无法自动提示导入&#xff1f;高亮显示与选中字符串相同的内容IDEA 配置 MavenIDEA 连接 Mysql 数据库 3 参考文章 1 下载与安装IDEA 首先先到官网下载…...

AI文本创作在百度App发文的实践

作者 | 内容生态端团队 导读 大语言模型&#xff08;LLM&#xff09;指包含数百亿&#xff08;或更多&#xff09;参数的语言模型&#xff0c;这些模型通常在大规模数据集上进行训练&#xff0c;以提高其性能和泛化能力。在内容创作工具接入文心一言AI能力后&#xff0c;可以为…...

Kafka 集群与可靠性

文章目录 Kafka集群的目标Kafka集群规模如何预估Kafka集群搭建实战Kafka集群原理成员关系与控制器集群工作机制replication-factor参数auto.leader.rebalance.enable参数 集群消息生产可靠的生产者ISR&#xff08;In-sync Replicas&#xff09;使用ISR方案的原因ISR相关配置说明…...

【刷题】蓝桥杯

蓝桥杯2023年第十四届省赛真题-平方差 - C语言网 (dotcpp.com) 初步想法&#xff0c;x y2 − z2&#xff08;yz)(y-z) 即xa*b&#xff0c;ayz&#xff0c;by-z 2yab 即ab是2的倍数就好了。 即x存在两个因数之和为偶数就能满足条件。 但时间是&#xff08;r-l&#xff09;*x&am…...

C++入门及简单例子_4

1. 类和对象&#xff1a; #include <iostream> // 包含输入输出流库的头文件class Rectangle { // 定义名为Rectangle的类 private: // 私有成员变量部分double length; // 长度double width; // 宽度public: // 公有成员函数部分Rectangle(double len, double w…...

成集云 | 用友U8集成聚水潭ERP(用友U8主管库存)| 解决方案

源系统成集云目标系统 方案介绍 用友U8是一套企业级的解决方案&#xff0c;可满足不同的制造、商务模式下&#xff0c;不同运营模式下的企业经营管理。它全面集成了财务、生产制造及供应链的成熟应用&#xff0c;并延伸客户管理至客户关系管理&#xff08;CRM&#xff09;&am…...

提升网站效率与SEO优化:ZBlog插件集成解决方案

在创建和管理网站的过程中&#xff0c;使用合适的工具和插件可以大幅提升效率&#xff0c;并改善搜索引擎优化&#xff08;SEO&#xff09;结果。ZBlog插件是为ZBlogCMS设计的一组工具&#xff0c;它们帮助网站管理员轻松地满足各种需求&#xff0c;从采集内容到发布、推送和SE…...

C语言的编译过程详解

当我们编译C程序时会发生什么&#xff1f;编译过程中的组件有哪些&#xff0c;编译执行过程是什么样的? 什么是编译 C语言的编译过程就是把我们可以理解的高级语言代码转换为计算机可以理解的机器代码的过程&#xff0c;其实就是一个翻译的过程。 …...

无人机航测没信号?北斗卫星来解决

无人机航测是利用无人机进行地理信息的采集和处理的航测方式。相比传统的航测手段&#xff0c;无人机航测具备更高的灵活性、更低的成本和更广阔的适应性。无人机航测可以应用于土地测绘、农业植保、城市规划、自然资源调查等多个领域&#xff0c;极大地提高了测绘的效率和准确…...

Vue 03 数据绑定

Vue中有2种数据绑定的方式&#xff1a; 1.单向绑定(v-bind)&#xff1a; 数据只能从data流向页面。 2.双向绑定(v-model)&#xff1a; 数据不仅能从data流向页面&#xff0c;还可以从页面流向data。 备注&#xff1a; 1.双向绑定一般都应用在表单类元素上&#xff08;如&am…...

#循循渐进学51单片机#步进电机与蜂鸣器#not.8

1、能够理解清楚单片机IO口的结构。 2)t1相当于PnP三级管&#xff0c;t2相当于npn三极管 3&#xff09; 强推挽io具有较强的驱动能力&#xff0c;电流输出能力很强。 2、能够看懂上下拉电阻的电路应用&#xff0c;并且熟练使用上下拉电阻。 3、理解28BYJ-48减速步进电机的工作…...

计算存储是不是智算时代的杀手锏?

想象一下&#xff0c;在一个繁忙的数据中心里&#xff0c;有一家大型互联网公司叫做“数据中心的故事”。这家公司一直在使用传统的CPU架构来处理海量数据。但是随着数据量的不断增长&#xff0c;CPU架构遇到了很多问题和瓶颈&#xff0c;这让“数据中心的故事”感到非常苦恼。…...

西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(二)

西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(二) 上一次和大家分享了组态相关的重要内容,具体可以参考以下链接中的内容: 西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(一) 本次继续和大家分享关于安全PLC基础编程的相关内容: 如下图所示,在左侧的…...

【Spring Boot】Spring Boot中的简单查询

前面介绍了在Spring Boot项目中集成JPA框架&#xff0c;实现数据的增、删、改、查等功能。Spring Data JPA的使用非常简单&#xff0c;只需继承JpaRepository即可实现完整的数据操作方法&#xff0c;无须任何数据访问层和SQL语句。JPA除了这些功能和优势之外&#xff0c;还有非…...

Transformer 01(自注意机制Self-attention)

一、Self-attention [台大李宏毅] 1.1 向量序列的输入 一个序列作为输入&#xff1a; 多个向量输入举例&#xff1a; 一个句子&#xff1a; 声音信号&#xff1a; 图&#xff1a; 1.2 输出 二、Sequence labeling 输入与输出一样多&#xff1a;Sequence labeling 窗口开的…...

交流共享,共筑智算底座丨九州未来受邀出席英特尔线下沙龙

随着AI技术的升级迭代、生成式AI模型智能化水平的持续提升&#xff0c;AIGC加速向多种场景渗透&#xff0c;AIGC迎来应用爆发期&#xff0c;有望实现且跨越更多领域的融合&#xff0c;形成新的应用场景和解决方案&#xff0c;持续推动数字技术的创新与应用&#xff0c;助力各行…...

【EI会议信息】第五届土木建筑与城市工程国际学术会议(ICCAUE 2023)

第五届土木建筑与城市工程国际学术会议&#xff08;ICCAUE 2023&#xff09; 2023 5th International Conference on Civil Architecture and Urban Engineering (ICCAUE 2023) 第五届土木建筑与城市工程国际学术会议&#xff08;ICCAUE 2023&#xff09;由天津大学主办&…...

上海亚商投顾:沪指震荡反弹 汽车产业链全天强势

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 大小指数昨日集体反弹&#xff0c;沪指3100点失而复得&#xff0c;创业板指一度涨超1.5%&#xff0c;随后涨幅…...

【Python深度学习】深度学习入门介绍

引言 深度学习是人工智能领域中最受关注和研究的子领域之一&#xff0c;它在计算机视觉、自然语言处理、语音识别、推荐系统等各个领域都有广泛的应用。本文将详细介绍深度学习的发展历史、不同类型、应用领域以及未来发展前景。 1、深度学习的发展历史 深度学习的起源可以追溯…...

【Linux系统编程】进程概念与基本创建

文章目录 1. 进程的概念2. 进程描述—PCB3. task_struct—PCB的一种4. task_ struct内容分类5. 查看进程 这篇文章我们来学习下一个概念——进程 1. 进程的概念 那什么是进程呢&#xff0c;我们该如何理解它呢&#xff1f; 如果我们打开电脑的任务管理&#xff1a; 我们看到这…...

制作灯笼图片/厦门百度seo点击软件

re模块\正则表达式 一、元字符 1、. ^ $ * ? { } [ ] | ( ) \ "."  代表&#xff08;任意一个字符&#xff09; "*"  代表&#xff08;任意数量任意字符&#xff0c;0-无穷&#xff09; ""  代表&#xff08;任意一个或无数字符&#xf…...

网站建设一六八互联/东莞搜索优化

本文授权转载自学术头条作者&#xff1a;赵雅琦前段时间&#xff0c;浙江高考满分作文《生活在树上》因为晦涩难懂的内容&#xff0c;刷爆了各种社交媒体。外行人看热闹&#xff0c;内行人看门道&#xff0c;大神们透过现象看本质。一般来说&#xff0c;高考作文可以通过批量化…...

看视频做那个网站好/重庆百度搜索优化

数据存储引擎&#xff1a;定义&#xff1a;什么是数据存储引擎作为插拔式的插件提供&#xff0c;是数据库 mysql 服务软件自带功能程序&#xff0c;是用来处理表的处理器。每一种的存储引擎都有不同的功能和数据存储方式1.1查看当前数据库服务&#xff0c;支持的存储以mysql>…...

邵阳网站建设公司/营销型企业网站的功能

ListIterator由JDK1.2开始添加&#xff0c;继承自Iterator。ListIterator是列表的迭代器&#xff0c;允许在任一方向上遍历列表&#xff0c;在迭代期间修改列表&#xff0c;并获取迭代器在列表中的当前位置。 接口中的方法&#xff1a; boolean hasNext();如果在正向遍历时&am…...

做企业网站好的/seo推广有哪些公司

有时我们需要在html元素的title中换行显示信息。以下几种方法均可以实现&#xff1a; 直接在titile属性中使用换行&#xff0c;如下所示&#xff1a;  1 <a href"asd"title"asdsad2 asdsad3 asd">asdsadsad</a>在title属性中使用AscII码&…...

唐山网站制作方案/电商项目策划书

二、 依赖属性的优先级 由于WPF 允许我们可以在多个地方设置依赖属性的值&#xff0c;所以我们就必须要用一个标准来保证值的优先级别。比如下面的例子中&#xff0c;我们在三个地方设置了按钮的背景颜色&#xff0c;那么哪一个设置才会是最终的结果呢&#xff1f;是Black、Red…...