彻底理解如何保证Redis和数据库数据一致性问题

一.背景

系统中缓存最常用的策略是:服务端需要同时维护 DB 和 Cache 并且是以 DB 的结果为准,那么就可能出现 DB 和 Cache 数据不一致的问题。

二.读数据

逻辑如下:

当客户端发起查询数据的请求,首先回去Redis中查看没有没该数据,有就返回,没有的话就需要去数据库中查询该数据,并且将该数据缓存在Redis中,然后设置一个过期时间(过期时间的作用就是为了保证一些冷数据能及时被清理,不长时间保存在Redis中,占用Redis的空间),保证在Redis后,返回数据到客户端,这是最常见的一个数据读取场景。

如果我们只读的话,肯定不会出现数据不一致问题,一般是读和写并发的时候才会出现数据不一致问题

三.写数据

分如下两种方式:

更新缓存再更新数据库,还是,先删除缓存再更新数据库;

更新数据库再更新缓存,还是,先更新数据库再删除缓存。

1.删除缓存还是更新缓存?

答:删除!这是因为更新操作相对来说更为复杂,涉及到数据的一致性和同步性等问题;而删除操作相对简单,只需要将缓存中的对应键值对删除即可;在实际的缓存场景中,我们经常会遇到数据更新的频繁性和数据量的大规模,如果每次更新操作都需要同步更新缓存,那么会增加系统的复杂性和开销,而采用只删不更新的方式,可以避免这些问题,当数据被修改时,我们只需要删除缓存中的对应键值对,下一次访问时再重新从数据库或其他数据源中获取最新的数据,并将其存储到缓存中,这种方式可以减少数据同步的开销,并且保证缓存数据的一致性。

2.先操作数据库还是缓存?

(1)先操作缓存

写的场景:先把Redis的数据删除,然后再写入数据库

读写并发场景,如何导致数据不一致:

1)线程1发起修改操作,然后删除Redis中的缓存,此时网络出现卡顿;

2)线程2由于是并发进来,他执行的是一个查询的请求,他会去Redis中查数据,查不到数据,所以会去数据库中查询,此时它查询的是老数据,并且会把数据缓存到Redis中;

3)线程1网络卡顿结束,并把最新数据更新到数据库中;

4)此时数据库是新数据,Redis是老数据,后面再有线程查询请求,请求到的都是老数据,必须等到老数据的过期时间到了,才能重新查询数据库获取到新数据,这个过程之间,一直都会数据不一致。 

解决方案:

线程1把数据库修改成新的后,再执行一遍删除Redis缓存操作,但是线程2查询到的肯定是老数据,所以只会出现数据的一次不一致

那能不能保证不一致一次都不出现?

这就需要引入强一致性概念,如果数据库和Redis是强一致性的话,就必须要保证他们的操作是原子性,因为我们的Redis和数据库是在不同服务器上的,如果要保证他们的操作原子性,就需要去上一把锁,但是加锁后会影响系统的性能,然而我们用Redis就是为了提高系统性能,此时又为了保证强一致性,又去加锁,这样就得不偿失了,所以说,强一致性和性能我们只能保证一种,AP和CP只能保证一种,我们在AP的基础上,就可以采用双删方式保证数据的一致性,虽然会出现一次数据不一致,但是Redis和数据库他们最终的数据都是最新的,所以我们要保存数据一致性的时候会采用这种最终一致性

双删的时候为什么要采用延迟删除?

如果不进行延迟删除,在线程1删除数据后,此时线程2才把老数据放入Redis中,此时的删除相当于没删,同样会出现数据不一致问题,所以需要采用延迟双删方式

延时双删过程:

1)先删除缓存;

2)写数据库;

3)休眠500毫秒,在删除缓存;

这样子最多其他线程在这500毫秒获取到脏数据,这是无法避免的,这个500毫秒不是固定的,需要结合项目的具体业务进行判定(线程2查数据库到放数据到Redis的时间来判定)。

(2)先操作数据库

 写的场景:先写入数据库,然后再把Redis的数据删除

读写并发场景,如何导致数据不一致:

1)线程1发起修改操作,写入数据到数据库,数据库为最新数据;

2)线程2同时并发进来,进行一个查询操作,查询到时老数据,直接返回;

3)线程1然后把Redis的老数据删除,其他线程在进来,查询Redis没有,就会直接查询数据库,并缓存最新数据到Redis。

这样操作下来,也能保证数据的最终一致性,所以推荐先操作数据库,再删除缓存,只是在操作数据库时,其他线程在这个过程中查询的是脏数据。

但是这个操作是否还有问题?

有!比如说数据库插入了最新数据后,删除缓存失败,后续线程进来查询都是老数据,也是需要等待Redis缓存时间过期才能查询到最新的,虽然这是比较极端的情况,但是还是有可能出现,针对删除失败的情况,我们可以采用删除缓存重试机制

可以在删除缓存失败后,异步发送需要删除的Key到MQ中,然后监听MQ,进行重试删除, 如果在设定的重新次数后,还是删除失败,就需要记录日志,让开发人员进行排查问题。

但是重试操作带来的后果就是加入MQ,所以逻辑都放在业务代码中,增加了代码的耦合性,那么要想解耦,可以使用另外一个组件Canal。

(3)Canal解耦

Canal是阿里的一款开源框架,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费,Canal提供了各种语言的客户端,当Canal监听到binlog变化时,会通知Canal的客户端,如下图:

我们可以利用Canal提供的Java客户端,监听Canal通知消息,当收到变化的消息时,完成对缓存的更新。

不管前面先删除缓存,还是先写数据库,最终在数据进行修改的时候,canal会从订阅到binlog日志中将变更的消息通知到canal客户端(Springboot应用),然后进行删除操作,如果删除失败,发送消息到MQ,进行重复删除,这些操作都是在canal客户端进行的,从而个根业务代码进行了解耦。

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

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

相关文章

后仿真中的SDF语法之关键字 IOPATH 用法详解

在后仿真中,SDF(Standard Delay Format)文件用于描述设计的时序信息,而IOPATH是SDF中的一个关键结构,用于定义单元间的路径延迟。以下是IOPATH关键字的用法及其相关内容的详细介绍: IOPATH结构旨在将延迟数…

Springboot 整合 Java DL4J 搭建智能问答系统

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…

基于SpringBoot的“网上书城管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“网上书城管理系统”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 系统首页界面图 用户注册界面…

测评部署和管理 WordPress 最方便的面板

新版宝塔面板快速搭建WordPress新手教程 - 倚栏听风-Morii - 博客园 初学者使用1Panel面板快速搭建WordPress网站 - 倚栏听风-Morii - 博客园 可以看到,无论是宝塔还是1Panel,部署和管理WordPress都有些繁琐,而且还需要额外去配置Nginx和M…

网络安全问题概述

1.1.计算机网络面临的安全性威胁 计算机网络上的通信面临以下的四种威胁: (1) 截获——从网络上窃听他人的通信内容。 (2) 中断——有意中断他人在网络上的通信。 (3) 篡改——故意篡改网络上传送的报文。可应用于域名重定向,即钓鱼网站。 (4) 伪造——伪…

视觉顶会论文 | 基于Swin Transformer的轴承故障诊断

往期精彩内容: Python-凯斯西储大学(CWRU)轴承数据解读与分类处理 Pytorch-LSTM轴承故障一维信号分类(一)-CSDN博客 Pytorch-CNN轴承故障一维信号分类(二)-CSDN博客 Pytorch-Transformer轴承故障一维信号分类(三)-CSDN博客 三十多个开源…

Altenergy电力系统控制软件 status_zigbee SQL注入漏洞复现(CVE-2024-11305)

0x01 产品简介 Altenergy电力系统控制软件是Altenergy Power System推出的一款专业软件。旨在为用户提供全面、高效、安全的电力系统控制解决方案。广泛应用于各类电力系统领域,如电力调度中心、发电厂、变电站、工业园区等。通过该软件的应用,用户可以实现对电力系统的全面…

java: spire.pdf.free 9.12.3 create pdf

可以用windows 系统中文字体,也可以从文件夹的字体文件 /*** encoding: utf-8* 版权所有 2024 ©涂聚文有限公司* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎* 描述:* # Author : geovindu,Geovin Du 涂…

AUTOSAR网络管理中的主动唤醒与被动唤醒

文章目录 1、主动/被动唤醒源、主动/被动唤醒节点2、网络拓扑说明 1、主动/被动唤醒源、主动/被动唤醒节点 休眠唤醒需要有一个触发源来进行触发,我们常用的NM报文是其中的载体之一。休眠唤醒的触发源又分为主动唤醒源和被动唤醒源。 主动唤醒源,就是能…

索贝融媒体 Sc-TaskMonitoring/rest/task/search SQL注入漏洞复现

0x01 产品简介 索贝融媒体产品是成都索贝数码科技股份有限公司(简称索贝)为各级电视台和媒体机构打造的一套集互联网和电视融合生产的解决方案。其代表产品为MCH2.0融合媒体生产业务系统,该系统带来了媒体领域一种全新的融合生产流程和工作机制,具有全方位的资源汇聚能力、…

【PyTorch】Pytorch中torch.nn.Conv1d函数详解

1. 函数定义 torch.nn.Conv1d 是 PyTorch 中用于一维卷积操作的类。定义如下: 官方文档:https://pytorch.ac.cn/docs/stable/generated/torch.nn.Conv1d.html#torch.nn.Conv1d torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride1,paddi…

[大数据]Trino

Trino安装部署-CSDN博客 Central Repository: io/trino/trino-server 下载地址: repo1.maven.org/maven2/io/trino/Central Repository: io/trino/trino-serverhttps://repo1.maven.org/maven2/io/trino/trino-server/ vim /etc/security/limits.conf * soft nofile 131072…

三种复制只有阅读权限的飞书网络文档的方法

大家都知道,飞书是一款功能强大的在线协作工具,可以帮助团队更高效地协作和沟通。越来越多的资料都在使用飞书文档,在使用飞书的过程中,发现很多文档没有复制权限,如果想要摘抄笔记,只能一个字一个字地敲出…

HTML5拖拽API学习 托拽排序和可托拽课程表

文章目录 前言拖拽API核心概念拖拽式使用流程例子注意事项综合例子🌰 可拖拽课程表拖拽排序 前言 前端拖拽功能让网页元素可以通过鼠标或触摸操作移动。HTML5 提供了标准的拖拽API,简化了拖放操作的实现。以下是拖拽API的基本使用指南: 拖拽…

缓冲区的奥秘:解析数据交错的魔法

目录 一、理解缓存区的好处 (一)直观性的理解 (二)缓存区的好处 二、经典案例分析体会 (一)文件读写流(File I/O Buffering) BufferedOutputStream 和 BufferedWriter 可以加快…

解决upload上传之后,再上传没有效果

解决upload上传之后,再上传没有效果 注释:这是第二次上传,两次网络请求都是第一次上传的,这次上传没有网络请求 原因:在我的代码里我限制了上传数量为1,然后上传成功后,上传列表没有清空&#…

【Linux】<共享内存应用>——模拟实现不同进程把hello字符对<共享内存文件对象>的放入和取出操作

前言 大家好吖,欢迎来到 YY 滴Linux系列 ,热烈欢迎! 本章主要内容面向接触过C Linux的老铁 主要内容含: 欢迎订阅 YY滴C专栏!更多干货持续更新!以下是传送门! YY的《C》专栏YY的《C11》专栏YY的…

Sigrity SPEED2000 TDR TDT Simulation模式如何进行时域阻抗仿真分析操作指导-差分信号

Sigrity SPEED2000 TDR TDT Simulation模式如何进行时域阻抗仿真分析操作指导-差分信号 Sigrity SPEED2000 TDR TDT Simulation模式如何进行时域阻抗仿真分析操作指导-单端信号详细介绍了单端信号如何进行TDR仿真分析,下面介绍如何对差分信号进行TDR分析,还是以下图为例进行分…

视频修复技术和实时在线处理

什么是视频修复? 视频修复技术的目标是填补视频中的缺失部分,使视频内容连贯合理。这项技术在对象移除、视频修复和视频补全等领域有着广泛的应用。传统方法通常需要处理整个视频,导致处理速度慢,难以满足实时处理的需求。 技术发…

golang调用webview,webview2,go-webview2

go version go1.20 windows/amd64 先要了解一些第三方库 1、webview/webview 它是一个跨平台的轻量级的webview库,面向的是C/C,使用它可以构建跨平台的GUI。webview就是浏览器内核,在不同操作系统上是不同的库,比如在windows上…