Redis和数据库一致性问题

news2025/4/19 0:15:27

操作模拟

1、先更新数据库还是先更新缓存?

1.1先更新缓存,再更新数据库

按并发的角度来说,有两个线程A、B,操作同一个数据,线程A先更新缓存为1,在线程A更新数据库之前,这时候线程B进来,更新缓存为2,更新数据库为2,这时候线程A更新数据库为1.

此时,缓存中数据为2,但数据库为1,缓存和数据库不一致

画板

因此先更新缓存,再更新数据库会有数据不一致的情况

1.2 先更新数据库,再更新缓存

我们再来进行分析。

线程A先更新数据库为1,还未更新缓存,这时候线程B更新数据库为2,缓存更新为2,最后线程A把缓存更新为1。

最后情况:缓存中为1,数据库中为2

画板

:::info
仍然会出现数据库和缓存不一致问题

:::

小结

【先更新缓存,再更新数据库】和【先更新数据库,再更新缓存】都有可能导致数据库和缓存不一致问题。既然这两者不一致,那么我们能否考虑去掉其中一个呢?当然不能删数据库,那就只能删缓存了。也就是后面的方法。在删缓存的顺序也有讲究。

2、先删缓存,还是先更新数据库?

2.1、先删除缓存,再更新数据库

同样使用多线程来分析,这时候使用读写进行分析。

写线程A进入,删除缓存,这时候°线程B进入,读取数据库值为1,更新缓存为1(由于更新缓存的操作是非常快的,因此出现这种情况的概率会比较大),最后线程A更新数据库为2,就会出现数据库和缓存不一致的情况。

画板

2.2、先更新数据库,再删除缓存

同样使多线程分析。

  • 线程A进入,先更新数据库为2,
  • 后面读线程B进入,读取数据为1
  • 然后线程A删除缓存
  • 线程B写入缓存为1

此时仍然会出现数据库与缓存不一致的情况,但是请注意,读取数据和写入缓存数据通常要快得多,因此出现这种情况的概率是比【先删缓存,再更新数据库】的概率低得多的,所以我们只需要再给缓存增加一个过期时间即可。

画板

删除缓存的操作可能会失败
使用消息队列发送请求

:::color2
- 这时候还可以引入消息队列(利用消息重试机制)来进行操作,将删除缓存放到消费者当中去。但是此方法会导致代码入侵,需要修改原来删缓存的业务代码,然后添加消息队列重试机制。

:::

订阅 MySQL binlog,再操作缓存

我们知道,mysql是有一个二进制日志文件的,当数据库产生更新操作时,就会计入该二进制文件中。

【先更新数据库,再删缓存】的策略的第一步是更新数据库,那么更新数据库成功,就会产生一条

变更日志,记录在 binlog里。

于是我们就可以通过订阅binlog日志,拿到具体要操作的数据,然后再执行缓存删除,阿里巴巴开

源的**Canal中间件**就是基于这个实现的。

Canal模拟MySQL主从复制的交互协议,把自己伪装成一个MySQL的从节点,向MySQL主节点

发送dump请求,MySQL收到请求后,就会开始推送Binlog给Canal,Canal解析 Binlog字节流

之后,转换为便于读取的结构化数据,供下游程序订阅使用。

Canal工作原理

前面我们说到直接用消息队列重试机制方案的话,会对代码造成入侵,那么Canal方案就能很好的

规避这个问题,因为它是直接订阅binlog日志的,和业务代码没有藕合关系,因此我们可以通过

Canal+消息队列的方案来保证数据缓存的一致性。

具体的做法是:

:::color1
将binlog日志采集发送到MQ队列里面,然后编写一个简单的缓存删除消息者订阅

binlog日志,根据更新log删除缓存,并且通过ACK机制确认处理这条更新log,保证数据缓存一致

性。这样,我们其实是在业务代码之外对缓存进行删除的,通过直接订阅mysql的binlog文件,而不是在业务代码中手动发送删除消息。

:::

总结

:::info
数据库和缓存保持一致性的问题,最简单快捷的方式就是【先更新数据库,再删除缓存】,但是这会导致缓存命中率变低,如果对缓存命中率有要求的系统,可以考虑【先更新缓存,再更新数据库】或者【先更新数据库,再更新缓存】的方式,但是需要加上锁机制进行线程互斥(把更新缓存和更新数据库的操作放在同步代码块内),这样才能避免多线程同时操作,导致数据库与缓存不一致的情况,但是这会导致写入性能下降。

:::

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

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

相关文章

第R8周:RNN实现阿尔茨海默病诊断(pytorch)

>- **🍨 本文为[🔗365天深度学习训练营]中的学习记录博客** >- **🍖 原作者:[K同学啊]** 本人往期文章可查阅: 深度学习总结 一、准备工作 🏡 我的环境: 语言环境:Python3.1…

C++基础精讲-02

文章目录 1.C/C申请、释放堆空间的方式对比1.1C语言申请、释放堆空间1.2C申请、释放堆空间1.2.1 new表达式申请数组空间 1.3回收空间时的注意事项1.4malloc/free 和 new/delete 的区别 2.引用2.1 引用的概念2.2 引用的本质2.3 引用与指针的联系与区别2.4 引用的使用场景2.4.1 引…

【网络安全】Linux 命令大全

未经许可,不得转载。 文章目录 前言正文文件管理文档编辑文件传输磁盘管理磁盘维护网络通讯系统管理系统设置备份压缩设备管理其它命令前言 在网络安全工作中,熟练掌握 Linux 系统中的常用命令对于日常运维、日志分析和安全排查等任务至关重要。 以下是常用命令的整理汇总,…

C++学习之ORACLE①

目录 1.ORACLE数据库简介 2..ORACLE数据库安装 3..ORACLE体系结构 4..ORACLE基本概念 5..ORACLE基本元素 6..ORACLE数据库启动和关闭 7.SQLPLUS登录ORACLE数据库相关操作 8.SQLPLUS的基本操作 9.oracle中上课使用的方案 10.SQL语言分类 11.SQL中的select语句语法和注…

企业级开发SpringBoost玩转Elasticsearch

案例 Spring Boot 提供了 spring-data-elasticsearch 模块,可以方便地集成 Elasticsearch。 下面我们将详细讲解如何在 Spring Boot 中使用 Elasticsearch 8,并提供示例代码。 1. 添加依赖: 首先,需要在 pom.xml 文件中添加 spring-data-e…

从零开始的图论讲解(1)——图的概念,图的存储,图的遍历与图的拓扑排序

目录 前言 图的概念 1. 顶点和边 2. 图的分类 3. 图的基本性质 图的存储 邻接矩阵存图 邻接表存图 图的基本遍历 拓扑排序 拓扑排序是如何写的呢? 1. 统计每个节点的入度 2. 构建邻接表 3. 将所有入度为 0 的节点加入队列 4. 不断弹出队头节点,更新其…

SpringBoot框架—启动原理

1.SpringBootApplication注解 在讲解启动原理之前先介绍一个非常重要的注解SpringBootApplication,这个注解在Springboot程序的入口文件Application.java中必须添加。SpringBootApplication是一个整合了三个核心注解的组合注解。 三个核心注解的作用机制&#xff1…

怎么检查网站CDN缓存是否生效

为什么要使用CDN缓存? 网站使用缓存可显著提升加载速度,减少服务器负载和带宽消耗,优化用户体验,增强架构稳定性,助力SEO优化,实现资源高效利用与性能平衡。 通过合理配置 CDN 缓存策略,可降低…

【自然语言处理】深度学习中文本分类实现

文本分类是NLP中最基础也是应用最广泛的任务之一,从无用的邮件过滤到情感分析,从新闻分类到智能客服,都离不开高效准确的文本分类技术。本文将带您全面了解文本分类的技术演进,从传统机器学习到深度学习,手把手实现一套…

vba讲excel转换为word

VBA将excel转换为word Sub ExportToWordFormatted() 声明变量Dim ws As Worksheet 用于存储当前活动的工作表Dim rng As Range 用于存储工作表的使用范围(即所有有数据的单元格)Dim rowCount As Long, colCount As Long 用于存储数据范围的行数和列数…

ubuntu安装openWebUI和Dify【自用详细版】

系统版本:ubuntu24.04LTS 显卡:4090 48G 前期准备 先安装好docker和docker-compose,可以参考我之前文章安装: ubuntu安装docker和docker-compose【简单详细版】 安装openWebUI 先docker下载ollama docker pull ghcr.nju.edu.c…

基于Flask的勒索病毒应急响应平台架构设计与实践

基于Flask的勒索病毒应急响应平台架构设计与实践 序言:安全工程师的防御视角 作为从业十年的网络安全工程师,我深刻理解勒索病毒防御的黄金时间法则——应急响应速度每提升1分钟,数据恢复成功率将提高17%。本文介绍的应急响应平台&#xff…

spark数据清洗案例:流量统计

一、项目背景 在互联网时代,流量数据是反映用户行为和业务状况的重要指标。通过对流量数据进行准确统计和分析,企业可以了解用户的访问习惯、业务的热门程度等,从而为决策提供有力支持。然而,原始的流量数据往往存在格式不规范、…

list的使用以及模拟实现

本章目标 1.list的使用 2.list的模拟实现 1.list的使用 在stl中list是一个链表,并且是一个双向带头循环链表,这种结构的链表是最优结构. 因为它的实现上也是一块线性空间,它的使用上是与string和vector类似的.但相对的因为底层物理结构上它并不像vector是线性连续的,它并没有…

【今日三题】小乐乐改数字 (模拟) / 十字爆破 (预处理+模拟) / 比那名居的桃子 (滑窗 / 前缀和)

⭐️个人主页:小羊 ⭐️所属专栏:每日两三题 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 小乐乐改数字 (模拟)十字爆破 (预处理模拟)比那名居的桃子 (滑窗 / 前缀和) 小乐乐改数字 (模拟) 小乐乐改数字…

基于 Qt 的图片处理工具开发(一):拖拽加载与基础图像处理功能实现

一、引言 在桌面应用开发中,图片处理工具的核心挑战在于用户交互的流畅性和异常处理的健壮性。本文以 Qt为框架,深度解析如何实现一个支持拖拽加载、亮度调节、角度旋转的图片处理工具。通过严谨的文件格式校验、分层的架构设计和用户友好的交互逻辑&am…

44、Spring Boot 详细讲义(一)

Spring Boot 详细讲义 目录 Spring Boot 简介Spring Boot 快速入门Spring Boot 核心功能Spring Boot 技术栈与集成Spring Boot 高级主题Spring Boot 项目实战Spring Boot 最佳实践总结 一、Spring Boot 简介 1. Spring Boot 概念和核心特点 1.1、什么是 Spring Boot&#…

虽然理解git命令,但是我选择vscode插件!

文章目录 2025/3/11 补充一个项目一个窗口基本操作注意 tag合并冲突已有远程,新加远程仓库切换分支stash 只要了解 git 的小伙伴,应该都很熟悉这些指令: git init – 初始化git仓库git add – 把文件添加到仓库git commit – 把文件提交到仓库…

idea 打不开terminal

IDEA更新到2024.3后Terminal终端打不开的问题_idea terminal打不开-CSDN博客

【JVM】JVM调优实战

😀大家好,我是白晨,一个不是很能熬夜😫,但是也想日更的人✈。如果喜欢这篇文章,点个赞👍,关注一下👀白晨吧!你的支持就是我最大的动力!&#x1f4…