Redis高级系列-缓存双写一致性

news2024/9/24 17:36:16

Redis高级系列-缓存双写一致性

文章目录

  • Redis高级系列-缓存双写一致性
    • 1. 什么叫做缓存双写一致性?
    • 2. 缓存双写一致性有那些解决方案?
      • 2.1 Cache Aside Pattern(旁路缓存模式)
        • 延迟双删
        • 重试删除
        • binlog订阅异步删除
      • 2.2 Read Through/Write Through(读写穿透)
        • 使用场景
      • 2.3 Write Behind(后写或异步写)
        • 使用场景
    • 3. 总结

1. 什么叫做缓存双写一致性?

Redis缓存双写一致性是指在更新数据库数据后,同时更新缓存数据以保持数据一致性的策略,总的来说,就是写入redis写入数据库的数据要保持一致

2. 缓存双写一致性有那些解决方案?

2.1 Cache Aside Pattern(旁路缓存模式)

旁路缓存模式,字面意思理解:缓存是旁路,缓存相对与应用程序和数据库是旁路,应用程序可以直接绕过缓存访问数据库

在Cache Aside模式中,应用程序首先从缓存中读取数据,如果缓存中不存在,则从数据库中读取数据,并将数据写入缓存中。在更新数据时,应用程序首先更新数据库中的数据,然后删除缓存中的数据。当下一次请求到来时,应用程序会从数据库中读取最新的数据,并将其写入缓存中

那为什么要先更新数据库在删除缓存了?我们再看看几种更新策略

策略是否是多线程场景现象
先删除缓存再更新数据库删除缓存成功但数据库更新失败应用程序从数据库中读到旧值
缓存删除成功但数据库再更新中…有并发读请求并发读请求从数据库读到旧值,并回写到redis,导致后续都从redis读取到旧值
先更新数据库再删除缓存数据库更新成功,但缓存删除失败应用程序从redis读取到旧值
数据库更新成功,但缓存再删除中…有并发读请求并发读请求读取到旧值
先更新缓存再更新数据库更新缓存成功但更新数据库失败缓存和数据库数据不一致(不推荐,一般数据库作为兜底方案)
更新缓存成功但数据库再更新中缓存和数据库数据不一致(不推荐,一般数据库作为兜底方案)
先更新数据库再更新缓存更新数据库成功但缓存更新失败应用程序读取到旧值
更新数据库成功但缓存再更新中…有并发读请求并发读请求读取到旧值
延迟双删

经过我们对Cache Aside Pattern四种方案的八种场景进行仔细分析,我们大体上确定了先更数据库再删缓存的方案。但是这种方案也并不完美,假设我们更新数据库成功了,删除缓存失败了,那么同样会出现一致性问题。为了解决这种场景下的一致性问题,我们进一步引入了延迟双删方案来解决。

  • 为什么要做两次缓存删除呢?

从上图“延迟双删”中我们可以很清晰地看到,数据库的更新是在首次的缓存删除成功后进行的,这样就有效避地免了“先更数据库再删缓存”方案中可能出现的数据库更新成功缓存删除失败导致的一致性问题。第二次的缓存删除是为了避免在执行更新数据库操作完成之前其它线程读取数据库并更新缓存而导致的一致性问题。

  • 为什么第二次缓存删除又要延迟执行呢?

试想,如果我们不做第二次的延迟删除,而是更新数据库后立即删除会出什么问题?有没有可能其它读请求线程在更新数据库之前读取了数据,并在第二次立即删除缓存之后更新了缓存。很明显,延迟删除就是为了让可能存在的其它读请求线程尽可能地在更新完缓存后再执行缓存删除操作。这样一通操作后,数据库是最新的数据了,缓存里没有数据,后面的读请求线程又可以拿到数据库的最新数据写入缓存了。

  • 延迟删除具体需要延迟多长时间?

对于这个具体需要延迟多长时间,其实没有绝对的标准,唯一的标准就是根据读请求的耗时来确定,读请求越耗时,延迟时间越长。一般情况下我们设置的延迟时间为1秒。

重试删除

在上面的延迟双删方案中,如果我们思考,其实还是有诸多问题的。比如:在延迟双删的读写场景中,如果第二次缓存删除失败了,同样会出现一致性问题。那么删除失败了,重试几次不就好了吗?基于这个思想我们进一步引入了重试删除方案来解决

重试删除确实很大程度上解决了一致性问题,并且逻辑非常简单。唯一的不足可能就是需要引入消息队列,并且业务代码也会有一定的侵入。那么有没有既能够保证最终一致性,又能够解耦的方案呢?我们继续往下面看

binlog订阅异步删除

binlog订阅异步删除确实也能解决一致性问题,对代码也无任何侵入,但是整个架构复杂,中小项目一般都用不上。

2.2 Read Through/Write Through(读写穿透)

该策略又被称为读穿/写穿策略,和CacheAside策略的缓存数据与数据库数据为准不同,该策略的核心是用户只与缓存层交互(应用程序只与缓存或者中间层、缓存抽象层交互),由缓存层与数据库通信,写入或读取数据。

在读取数据时,通过缓存层进行读取,若缓存存在则直接返回,若不存在则由缓存层拉取数据库数据到缓存中并返回。
在写数据时,通过缓存层进行写入,若缓存存在则直接写入缓存中并同步到数据库,若不存在则写入数据库中。

使用场景

适用于读多写多的场景,数据一致性要求较高的场景。

2.3 Write Behind(后写或异步写)

Write Behind Caching是一种将缓存和数据库异步写入的缓存模式。在Write Behind Caching模式中,应用程序首先将更新操作写入缓存中,然后异步地将更新操作写入数据库中。当下一次请求到来时,应用程序会从缓存中读取数据,并将其写入数据库中。

使用场景

适用于写多读少的场景,数据一致性要求不高的场景

3. 总结

在使用Redis缓存时,应根据具体的业务场景和需求选择合适的缓存模式。Cache Aside模式简单易用,适用于读多写少的场景;Read/Write Through模式完全解耦缓存和数据库,适用于读多写多的场景;Write Behind Caching模式可以提高写入性能,适用于写多读少的场景。在实际应用中,可以根据具体的业务需求和性能要求,选择合适的缓存模式,以提高系统的性能和稳定性。

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

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

相关文章

爬虫之牛刀小试(八):爬取微博评论

今天爬取的是微博评论。 可以发现其特点是下一页评论的max_id在上一页中。 于是代码如下: import requests import json import re import time headers {User-Agent: ,"Cookie": "","Referer": "https://m.weibo.cn/detail/4…

Elasticsearch 数据类型相关总结:快速参考指南【记录】

在Elasticsearch中,有多种数据类型可用于定义字段。 在开始了解数据类型之前,首先要知道,在Elasticsearch中,分词处理主要针对文本字段,而对于其他类型字段(如数值、日期、布尔等),通…

绑定class,条件渲染,列表过滤,列表排序

目录​​​​​​​ 绑定class 条件渲染 列表过滤 列表排序 绑定class <div class"normal" :class"mood" click"changename">111{{name}}</div><div class"normal" :class"arr">111{{name}}</div…

使用golang对接微软Azure AI翻译

文章目录 一、官方地址二、准备工作三、代码示例 一、官方地址 https://learn.microsoft.com/zh-CN/azure/ai-services/translator/translator-text-apis?tabsgo 二、准备工作 创建服务 创建服务连接地址&#xff1a;https://portal.azure.com/#create/Microsoft.CognitiveS…

零基础学Python(3)— 注释、代码缩进和编码规范

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。在使用Python语言进行编程的时候&#xff0c;需要遵循一定的规范标准。本节课就带大家了解下Python语言在注释、缩进和编码方面的规范!~&#x1f308; 目录 &#x1f680;1.注释 &#x1f680;2.代码缩进 &#x1f68…

1.15io网络

子网掩码 1.由于对于一个网络下面的主机号还是很庞大&#xff0c;为了进一步划分网络&#xff0c;我们可以将主机号再次进行划分为两部分&#xff0c;分别是网段号和主机号 2.此时就引入的子网掩码的概念 3. 在引入子网掩码后&#xff0c;IP 网络号 子网号 主机号 4.子网…

UI设计中的插画运用优势(上)

1. 插画是设计的原创性和艺术性的基础 无论是印刷品、品牌设计还是UI界面&#xff0c;更加风格化的插画能够将不同的风格和创意加入其中&#xff0c;在激烈的竞争中更容易因此脱颖而出。留下用户才有转化。 2. 插画是视觉触发器&#xff0c;瞬间传达大量信息 我们常说「一图胜千…

【ARMv8M Cortex-M33 系列 7.1 -- xPSR | CFSR | HFSR | BFAR | MMFAR 寄存器】

文章目录 问题背景Cortex-M33 Fault 寄存器介绍xPSR (程序状态寄存器)CFSR (可配置故障状态寄存器)HFSR (硬件故障状态寄存器)BFAR (总线故障地址寄存器)MMFAR (内存管理故障地址寄存器) 问题背景 由于在RA4M2&#xff08;Cortex-M33&#xff09;移植RT-Thread OS的时候遇到了…

数据结构和算法笔记4:排序算法-归并排序

归并排序算法完全遵循分治模式。直观上其操作如下&#xff1a; 分解&#xff1a;分解待排序的n个元素的序列成各具n/2个元素的两个子序列。解决&#xff1a;使用归并排序递归地排序两个子序列。合并&#xff1a;合并两个已排序的子序列以产生已排序的答案。 我们直接来看例子…

ubuntu-20.04.6-live-server-amd64安装教程-完整版

简介 Ubuntu 20.04.6 Live Server AMD64 安装教程 - 完整版" 提供了详细的指南&#xff0c;旨在帮助用户在使用 AMD64 架构的服务器上安装 Ubuntu 20.04.6 Live Server 版本。该教程包含全面的步骤和详细说明&#xff0c;使用户能够顺利完成整个安装过程&#xff0c;建立…

力扣70. 爬楼梯(动态规划 Java,C++解法)

Problem: 70. 爬楼梯 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 由于本题目中第i层台阶只能由于第i- 1层台阶和第i-2层台阶走来&#xff0c;所以可以联想到动态规划&#xff0c;具体如下&#xff1a; 1.定义多阶段决策模型&#xff1a;对于每一上台阶看作一种状…

【LGR-172-Div.4】洛谷入门赛 #19(A—H,c++详解!)

文章目录 【LGR-172-Div.4】洛谷入门赛 #19A.分饼干 I题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示样例解释 1样例解释 2数据范围与约定思路: 代码 B.分饼干 II题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样…

SpringMVC基础知识学习笔记

Universe Infinity Inc. 目录 一、学习SpringMVC主要是学什么1、SpringMVC的基本原理2、SpringMVC学习串联 二、快速体验SpringMVC的开发1、新建项目&#xff0c;转成web项目2、引入依赖3、编写Spring的配置类4、配置web启动类&#xff0c;替代web.xml5、编写Handler&#xff…

助力焊接场景下自动化缺陷检测识别,基于YOLOv3模型开发构建工业焊接场景下缺陷检测识别分析系统

焊接是一个不陌生但是对于开发来说相对小众的场景&#xff0c;在我们前面的博文开发实践中也有一些相关的实践&#xff0c;感兴趣的话可以自行移步阅读即可&#xff1a; 《轻量级模型YOLOv5-Lite基于自己的数据集【焊接质量检测】从零构建模型超详细教程》 《基于DeepLabV3Pl…

令牌桶算法与Guava的实现RateLimiter源码分析

令牌桶算法与Guava的实现RateLimiter源码分析 令牌桶RateLimiter简介RateLimiter使用示例导入maven依赖编写测试代码 RateLimiter的实现源码解析SmoothRateLimiterSmoothBursty恒速获取令牌acquire(int)tryAcquire(int,long,TimeUnit) 存量桶系数小结 优缺点与漏桶的区别总结 令…

01-开始Rust之旅

1. 下载Rust 官方推荐使用 rustup 下载 Rust&#xff0c;这是一个管理 Rust 版本和相关工具的命令行工具。下载时需要连接互联网。 这边提供了离线安装版本。本人学习的机器环境为&#xff1a; ubuntu x86_64&#xff0c;因此选用第②个工具链&#xff1b; 1. rust-1.75.0-x86_…

CloudPanel RCE漏洞复现(CVE-2023-35885)

0x01 产品简介 CloudPanel 是一个基于 Web 的控制面板或管理界面,旨在简化云托管环境的管理。它提供了一个集中式平台,用于管理云基础架构的各个方面,包括虚拟机 (VM)、存储、网络和应用程序。 0x02 漏洞概述 由于2.3.1 之前的 CloudPanel 具有不安全的文件管理器 cook…

【JSON2WEB】01 WEB管理信息系统架构设计

WEB管理信息系统分三层设计&#xff0c;分别为DataBase数据库、REST2SQL后端、JSON2WEB前端&#xff0c;三层都可以单独部署。 1 DataBase数据库 数据库根据需要选型即可&#xff0c;不需要自己设计开发&#xff0c;一般管理信息系统都选关系数据库&#xff0c;比如Oracle、…

beego的模块篇 - I18n国际化

1. i18n 安装导入 安装该模块&#xff1a; go get github.com/beego/i18n 导入引用包&#xff1a; import ("github.com/beego/i18n" ) conf 目录下就有 locale_en-US.ini 和 locale_zh-CN.ini 两个本地化文件。 本地化文件的文件名和后缀是随意的&#xff0c;不…

C++_Lambda表达式的完整介绍

目录 1. 什么是Lambda表达式 1.1 四种表达式的含义 1.2 lambda表达式各个成员的解释 2. 捕获列表 3. 编译器如何看待Lambda表达式 参考文章 参考: C Lambda表达式的完整介绍 - 知乎 c在c11标准中引入了lambda表达式&#xff0c;一般用于定义匿名函数&#xff0c;使得代码…