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

如何保证Redis与Mysql双写一致性?

https://www.cnblogs.com/coderacademy/p/18137480

延迟双删

对于上面链接的文章,里面的延迟双删没有给出具体的例子,也没有直接指出具体解决的问题是针对那种缓存策略,这里补充一下,延时双删缓存针对的是Cache aside pattern(缓存旁路策略),处理的是在高并发读写同时存在的情况下可能会出现的问题,详细如下。

什么是延迟双删:

延时双删策略能够有效解决缓存和数据库之间的数据不一致问题。它的核心思想是在更新数据库之后,先删除缓存中的数据,延迟一段时间后再次删除缓存中的数据。其具体步骤如下:

  1. 更新数据库:先将数据更新到数据库中。
  2. 删除缓存:立即删除缓存中对应的旧数据。
  3. 延迟一段时间:等待一段时间(通常是足够长以保证并发写入完成的时间)。
  4. 再次删除缓存:再次删除缓存中的数据,以防止并发操作在缓存中留下旧数据。

tips:延迟双删需要由更新数据的那个程序去处理。

延时双删策略的应用场景

延时双删策略的应用场景通常涉及**高并发写操作**和**读取操作**同时发生的情况。以下是一个典型的具体场景,展示如何出现缓存和数据库数据不一致的问题。

### 场景描述

假设有一个电商网站,使用缓存(如 Redis)来加速商品信息的读取。例如,一个商品的库存信息存储在数据库中,同时也缓存到 Redis 中,以便快速读取。

#### 具体流程

1. **用户A请求读取商品库存信息:**
   - 用户A请求读取某个商品的库存信息,系统会优先从缓存(Redis)中读取该商品的库存。如果缓存中存在,则直接返回;如果不存在,则从数据库读取并将结果缓存起来。

2. **用户B请求更新商品库存信息:**
   - 在用户A读取缓存中的商品库存时,用户B执行了一个购买操作,该操作会更新商品的库存信息。系统会先更新数据库中的商品库存,然后删除缓存中的商品库存信息,以确保下一次读取时会从数据库中获取最新数据。

#### 问题出现

在用户B更新商品库存后,但**在删除缓存之后、更新数据库完成之前的时间窗口**内,用户A再次读取商品库存信息。这会出现以下问题:

- 用户B更新库存后,缓存被删除,但是用户A此时发起读取请求,因为缓存已经被删除,系统会去数据库中读取库存数据。
- 但数据库还没有完成更新操作(可能因为写入操作较慢,或者在执行事务),用户A读取到的仍然是旧的库存信息。
- 最后,数据库更新完成,数据正确,但用户A刚刚读取到了错误(旧)的库存数据,导致**数据不一致**。

### 延时双删策略如何解决这个问题

为了防止上述数据不一致情况的发生,可以使用延时双删策略:

1. **用户B更新商品库存信息:**
   - 更新数据库中的库存信息。
   - **立即删除缓存**中的商品库存信息。
   
2. **用户A读取商品库存信息:**
   - 如果在缓存被删除之后读取,系统会从数据库中读取。
   - 用户A读取时可能得到旧数据(数据库尚未更新完成),但接下来的延时操作将解决这个问题。
   
3. **延迟删除缓存:**
   - 设置一个延迟(例如 500 毫秒),在此延迟之后,再次尝试删除缓存中的商品库存信息。
   - 这段延迟时间应足够长,以确保数据库更新操作已经完成。

### 具体应用中的时间点

- **T1:用户B请求更新库存,系统开始更新数据库。**
- **T2:用户B更新数据库后,立即删除缓存。**
- **T3:数据库更新操作未完成,用户A读取库存,发现缓存不存在,转向读取数据库。**
- **T4:用户A读取到旧的库存数据(数据库写操作未完成)。**
- **T5:延迟一段时间(如500毫秒),再次删除缓存。**
- **T6:用户A再次请求,发现缓存不存在,此时数据库已更新,读取到最新库存信息。**

### 为什么这个策略有效

1. **避免读取旧数据**:通过在更新数据库后立即删除缓存,避免缓存中存在旧数据。
2. **降低不一致的窗口期**:延迟删除缓存提供了一个补偿机制,以防止在数据库写入完成前的缓存穿透现象。
3. **高效读取最新数据**:第二次删除缓存确保了之后的读取操作总能获取最新数据,减少了缓存和数据库之间的数据不一致的风险。

### 总结

延时双删策略主要解决的是在缓存删除和数据库更新之间的短时间窗口内出现数据不一致的问题,特别适用于**高并发写操作和读操作混合**的场景,如电商库存更新、金融交易系统的账户余额更新等。通过这种策略,系统能够更好地保障缓存和数据库之间的数据一致性。

延迟双删除golang代码示例

package mainimport ("context""fmt""time""go.mongodb.org/mongo-driver/bson""go.mongodb.org/mongo-driver/mongo""go.mongodb.org/mongo-driver/mongo/options"
)func main() {// 示例:更新数据库并执行延时双删策略// 示例的数据库操作ctx := context.Background()// 第一步:更新数据库updateDatabase(ctx)// 第二步:立即删除缓存deleteCache()// 第三步:设置一个延迟任务(如 500 毫秒)time.AfterFunc(500*time.Millisecond, func() {deleteCache() // 再次删除缓存})fmt.Println("Database update and delayed cache deletion scheduled.")
}func updateDatabase(ctx context.Context) {// 示例数据库更新操作fmt.Println("Updating database...")// 在此处执行数据库的更新操作...
}func deleteCache() {// 示例缓存删除操作fmt.Println("Deleting cache...")// 在此处执行缓存删除操作...
}

Read-Through 和Cache Aside Pattern的读有什么区别

**Read-Through** 和 **Cache Aside Pattern**(又称为 **Lazy Loading** 或 **Lazy Caching**)是两种常见的缓存策略,它们在缓存读取(读)操作的实现上有一些关键区别。

### Read-Through 缓存策略

**Read-Through** 是一种由缓存层自动管理数据加载的策略,读操作首先检查缓存,如果缓存中没有数据,缓存层会自动从后端数据源(例如数据库)加载数据并将其存储到缓存中,然后返回给调用者。

#### 工作原理

1. **应用程序请求数据**:
   - 应用程序向缓存层请求数据。
2. **缓存层检查数据**:
   - 如果缓存中有数据,直接返回。
   - 如果缓存中没有数据,缓存层会自动从后端数据源(如数据库)加载数据。
3. **缓存层更新缓存**:
   - 将从后端数据源获取的数据存储到缓存中,以便下次快速访问。
4. **返回数据**:
   - 缓存层返回数据给应用程序。

#### 特点

- **自动加载数据**:缓存层自动处理缓存未命中的情况,将数据从后端数据源加载到缓存中。
- **透明性**:应用程序不需要关心数据从哪里来,缓存层会自动管理。
- **常用于缓存代理中**:例如,使用特定的缓存中间件或服务来管理缓存。

#### 例子

如使用 AWS ElastiCache 或 Memcached 的集成模式,其中缓存中间件自动处理数据加载和缓存更新。

### Cache Aside Pattern 缓存策略

**Cache Aside Pattern**(Lazy Loading)是一种由应用程序主动管理缓存的数据加载的策略。应用程序在读取数据时首先检查缓存,如果缓存未命中,应用程序会主动从后端数据源加载数据并手动将数据写入缓存。

#### 工作原理

1. **应用程序请求数据**:
   - 应用程序首先检查缓存中是否有数据。
2. **缓存未命中时应用程序加载数据**:
   - 如果缓存中没有数据,应用程序从后端数据源(如数据库)加载数据。
3. **应用程序更新缓存**:
   - 应用程序将从后端数据源获取的数据写入缓存。
4. **返回数据**:
   - 应用程序返回数据给调用者。

#### 特点

- **主动管理缓存**:应用程序负责检查缓存、加载数据和更新缓存。
- **灵活性**:应用程序可以决定何时加载和更新数据,缓存的逻辑在应用程序中控制。
- **常用于手动控制缓存的场景**:例如,通过代码来管理缓存操作。

#### 例子

在 Go、Java 或 Python 应用中,程序员在业务逻辑中手动管理从缓存中读取数据,未命中时从数据库加载数据,并将其写入缓存的操作。

### 区别

| 特性                          | Read-Through                                          | Cache Aside Pattern                                 |
|-------------------------------|-------------------------------------------------------|-----------------------------------------------------|
| **数据加载责任**              | 缓存层自动负责从后端加载数据                           | 应用程序负责加载数据和更新缓存                      |
| **实现难度**                  | 较低,缓存层自动管理数据加载                           | 较高,应用程序需要管理缓存逻辑                      |
| **灵活性**                    | 较低,缓存策略由缓存层定义                             | 较高,应用程序可以控制何时加载和更新数据            |
| **常见使用场景**              | 通常用于缓存中间件或代理(如 Memcached, AWS ElastiCache)| 手动管理缓存的应用程序                              |
| **缓存未命中后的开销**        | 缓存层负责处理加载,应用程序不感知                      | 应用程序处理加载逻辑,有可能影响性能                |
| **读写操作的复杂度**          | 读操作简单,缓存层透明处理                             | 读操作复杂,需要在应用中显式处理缓存和数据库访问    |

### 总结

- **Read-Through** 更适合希望透明缓存管理的场景,使用缓存中间件或代理自动处理数据加载,简化应用逻辑。
- **Cache Aside Pattern** 更适合需要灵活控制缓存逻辑的场景,应用程序可以根据业务需求主动决定何时加载和更新缓存。

相关文章:

如何保证Redis与Mysql双写一致性?

https://www.cnblogs.com/coderacademy/p/18137480 延迟双删 对于上面链接的文章,里面的延迟双删没有给出具体的例子,也没有直接指出具体解决的问题是针对那种缓存策略,这里补充一下,延时双删缓存针对的是Cache aside pattern(缓…...

9.8笔试记录

1.在c中哪些运算符不能重载? 在 C 中,有以下几个运算符不能被重载: . :成员访问运算符。例如obj.member中的.不能被重载。 :: :作用域解析运算符。用于指定命名空间、类等的作用域,不能被重载。 ?: &#xff1…...

SRE-系统管理篇

SRE-系统管理篇 进程管理 进程的概念: 运行起来的程序,命令,服务等等都可以称作进行,进程都是运行在内存当中的。 程序的概念: 一般指安装包,程序代码,应用它们存放在磁盘上面的。 守护进程的概念: 守护进程,一直运行的进程,也可以叫做服务。 进程的分类 僵…...

傅里叶级数,傅里叶变换

先读文章:傅里叶分析之掐死教程(完整版)更新于2014.06.06 - 知乎 (zhihu.com) 傅里叶级数 一、内容:每个周期性函数都可以表示为无穷多个不同频率的正弦函数的叠加。 二、公式: 三、从时域到频域所保留的三点信息&…...

零知识证明在BSV网络上的应用

​​发表时间:2023年6月15日 2024年7月19日,BSV区块链主网上成功通过使用零知识证明验证了一笔交易。 零知识证明是一种技术,它允许一方(证明者)在不透露任何秘密的情况下,向另一方(验证者&…...

无任何门槛!3分钟5步,发布属于你的第一个智能体小程序,99%的人还不知道怎么用

相信大家都用微信小程序,但是大部分人应该还没有过属于自己的小程序吧。 今天程哥就带大家花三分钟用五步,来创建一个属于自己的微信小程序。 之前Coze在发布渠道里也有发布小程序的渠道,但是试过的人都知道,这个是有一定门槛的…...

怎么强制撤销excel工作表保护?

经常不是用的Excel文件设置了工作表保护,偶尔打开文件的时候想要编辑文件,但是发现忘记了密码,那么这种情况,我们怎么强制撤销excel工作表保护?今天分享两种解决方法。 方法一、 将excel文件转换为其他文件格式&…...

每天学习一个字符串类函数之memmove函数

目录 前言: 一、头文件 二、memmove函数的作用 三、理解memmove函数的定义 1、返回类型 2、参数 四、使用memmove函数 案例1: 案例2: 五、解决数据拷贝之前被覆盖的方法 六、模拟实现memmove函数 前言: 上一篇博客,我…...

【机器人工具箱Robotics Toolbox开发笔记(十三)】三自由度机器人圆弧轨迹规划仿真实例

在实际应用场景中,我们通常预先明确了目标末端的运动轨迹,随后引导机器人进行相应的动作。本实例具体展示了如何基于给定的两个点,计算出末端的精确位姿,并以此为基础,进一步规划出一条平滑的圆弧轨迹供机器人执行。这样的流程确保了机器人能够沿着预定的路径,精准且高效…...

软件工程-图书管理系统的概要设计

软件概要设计说明书 目录 软件概要设计说明书 一、引言 1.1 编写目的 1.2 背景 1.3 定义 1.3.1特定对象 1.3.2专业术语 1.4 参考资料 二、总体设计 2.1 需求规定 2.1.1信息要求 2.1.2功能要求 2.2 运行环境 2.3 基本概要设计和处理流程 2.4 体系结构设计 2.5 模…...

springboot 整合swagger

没有多余废话&#xff0c;就是干 spring-boot 2.7.8 springfox-boot-starter 3.0.0 结构 POM.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/…...

Flutter 进阶:绘制加载动画

绘制加载动画&#xff1a;由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类&#xff1a;LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态&#xff0c;而 Load…...

【深度学习】梯度下降法

梯度就是导数&#xff0c;而梯度下降法就是一种通过求目标函数的导数来寻找目标函数最小化的方法。梯度下降目的是找到目标函数最小化时的取值所对应的自变量的值&#xff0c;目的是为了找自变量X。 最优化问题在机器学习中有非常重要的地位&#xff0c;很多机器学习算法最后都…...

基于机器学习的电商优惠券核销预测

1. 项目简介 随着移动互联网的快速发展&#xff0c;O2O&#xff08;Online to Offline&#xff09;模式已成为电商领域的一大亮点。优惠券作为一种有效的营销工具&#xff0c;被广泛应用于吸引新客户和激活老用户。然而&#xff0c;传统的随机投放方式往往效率低下&#xff0c;…...

PHP-FPM 远程代码执行漏洞(CVE-2019-11043)复现

启动环境 切换目录到vulhub/php/CVE-2019-11043下 查看端口 访问 安装漏洞利用工具 git clone https://github.com/neex/phuip-fpizdam.git 安装go语言 # 1、下载go&#xff0c;这里使用 go1.22.5 版本&#xff0c;可替换为最新版本 wget https://dl.google.com/go/go1.22.5.…...

Rust : 从事量化的生态现状与前景

Rust适不适合做量化工作&#xff1f; 一般地认为&#xff0c;目前大部分场景策略开发最佳是Python&#xff1b;策略交易和部署是C。但还是有人会问&#xff0c;Rust呢&#xff1f; 这个问题不太靠谱&#xff01; 适不适合做一件事情&#xff0c;本身就是一件主观的事。即使是…...

Java项目——苍穹外卖(一)

Entity、DTO、VO Entity&#xff08;实体&#xff09; Entity 是表示数据库表的对象&#xff0c;通常对应数据库中的一行数据。它通常包含与数据库表对应的字段&#xff0c;并可能包含一些业务逻辑。 DTO&#xff08;数据传输对象&#xff09; 作用&#xff1a;DTO 是用于在…...

20240908 每日AI必读资讯

新AI编程工具爆火&#xff1a;手机2分钟创建一个APP&#xff01; - AI初创公司Replit推出的智能体——Replit Agent。开发环境、编写代码、安装软件包、配置数据库、部署等等&#xff0c;统统自动化&#xff01; - 操作方式也是极其简单&#xff0c;只需一个提出Prompt的动作…...

HNU-2023电路与电子学-实验3

写在前面&#xff1a; 本次实验是完成cpu设计的剩余部分&#xff0c;整体难度比上一次要小&#xff0c;细心完成就能顺利通过全部测评 一、实验目的 1.了解简易模型机的内部结构和工作原理。 2.分析模型机的功能&#xff0c;设计 8 重 3-1 多路复用器。 3.分析模型机的功能…...

html基础语法 看这一篇就够了!

HTML 一 概念 html:html 文件根标签 head:编写页面相关的属性 title:页面标题 body:页面内容展示信息 二 DOM 树&#xff1a; 所有的标签都是 html 的子标签 head 和 body 是兄弟标签&#xff0c;同一级别 head 和 title 为父子标签 1.第一个程序 <html><head>…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案

一、延迟敏感行业面临的DDoS攻击新挑战 2025年&#xff0c;金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征&#xff1a; AI驱动的自适应攻击&#xff1a;攻击流量模拟真实用户行为&#xff0c;差异率低至0.5%&#xff0c;传统规则引…...

RLHF vs RLVR:对齐学习中的两种强化方式详解

在语言模型对齐&#xff08;alignment&#xff09;中&#xff0c;强化学习&#xff08;RL&#xff09;是一种重要的策略。而其中两种典型形式——RLHF&#xff08;Reinforcement Learning with Human Feedback&#xff09; 与 RLVR&#xff08;Reinforcement Learning with Ver…...

Python爬虫(52)Scrapy-Redis分布式爬虫架构实战:IP代理池深度集成与跨地域数据采集

目录 一、引言&#xff1a;当爬虫遭遇"地域封锁"二、背景解析&#xff1a;分布式爬虫的两大技术挑战1. 传统Scrapy架构的局限性2. 地域限制的三种典型表现 三、架构设计&#xff1a;Scrapy-Redis 代理池的协同机制1. 分布式架构拓扑图2. 核心组件协同流程 四、技术实…...