数据库与缓存一致性如何保证

news2024/11/18 19:59:25

最近建了一个技术交流群,欢迎志同道合的同学加入,群里主要讨论:分享业务解决方案、深度分析面试题并解答工作中遇到的问题,同时也能为我提供写作的素材。

欢迎加Q:312519302,进群讨论

前言

在工作中,大多数的系统都在使用缓存,那你有没有想过为什么要使用缓存?使用缓存后,数据与缓存的一致性如何保证?

带着上面的问题,我们一起探索。

我们刚开始做一个项目的时候,刚起步,流量很小,直接读写数据库即可,性能不错,系统稳定,架构如下图:

随时时间推移,系统运行一段时间,老板说,要推广我们的系统,给用户赋能,接着搞一波营销,流量激增,结果系统报警了,系统都快挂了,赶紧排查,发现性能瓶颈在数据库

这好办,给服务器加上 Redis,让其作为数据库的缓存。

这样,在客户端请求数据时,如果能在缓存中命中数据,那就查询缓存,不用在去查询数据库,从而减轻数据库的压力,提高服务器的性能。

那我们的架构变为:

看起来非常美好,但是有个问提挡在我们面前,如果数据库的数据有修改的时候,我们是先更新数据库,还是先更新缓存呢

由于引入了缓存,那么在数据更新时,不仅要更新数据库,而且要更新缓存,这两个更新操作存在前后的问题

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

想了想,为了保证数据是最新的数据,那我们选择 先更新数据库,再更新缓存, 一顿操作猛如虎,系统优化完成后,上线,数据库压力也下来,吞吐量得到明显的提高,心里那个激动啊,我TM真是牛逼,等着老板的嘉奖。

过了一段时间后,有人反馈,我修改了数据后,查看详情,发现数据没变,但是我修改数据的时候,提示我修改成功。擦,难道是系统出bug了?

登录服务器排查,没发现有更新数据库、缓存的失败的信息,但是发现个问题,缓存是修改前的数据,数据是修改后的数据,那这种问题是怎么产生的呢?

进一步分析,发现缓存与数据库不一致的原因是并发导致的

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

并发为什么能导致数据与缓存不一致呢,我们接着分析,我举个例子,用户A与用户B同时修改一条数据

执行步骤:

  1. 用户A更新数据库为1
  2. 用户B更新数据库为2****
  3. 用户B更新缓存2
  4. 用户A更新缓存为1

从上面可以看出,数据库为2,缓存也应该为1,这就造成了缓存与数据库不一致的现象

如果我们先更新缓存,再更新数据库呢?

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

执行步骤:

  1. 用户A更新缓存为1
  2. 用户B更新缓存2
  3. 用户B更新数据库为2
  4. 用户A更新数据库为1

从上面可以看出,数据库为1,缓存也应该为2,还是造成了缓存与数据库不一致的现象


结论: 无论是先更新数据库,再更新缓存,还是先更新缓存,再更新数据库,在并发访问修改一条数据的时候,都会出现不一致的情况

想了想,那不更新缓存了,直接删除缓存。也就是数据库后更新后,直接删除缓存。 在读取数据的时候,查看缓存中有没有数据,没有数据查询数据库,然后再更新缓存。

这个策略有个名字:Cache Aside 策略, 中文:旁路缓存策略

旁路缓存策略

Cache Aside(旁路缓存)策略是最常用的,应用程序直接与「数据库、缓存」交互,并负责对缓存的维护,该策略又可以细分为「读策略」和「写策略」。

写策略的步骤:

  • 先更新数据库中的数据,再删除缓存中的数据。

读策略的步骤:

  • 如果读取的数据命中了缓存,则直接返回数据;
  • 如果读取的数据没有命中缓存,则从数据库中读取数据,然后将数据写入到缓存,并且返回给用户。

问题来了,那我们是先更新数据库,再删除缓存还是先删除缓存,再更新数据库?

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

执行步骤:

  1. 用户A删除缓存
  2. 用户B查询缓存,缓存中没有数据
  3. 用户B查询数据库,得到数据
  4. 用户B更新缓存数据
  5. 用户A更新数据库为最新的值

从结果看,缓存的是旧值:1,数据库是最新值:2,在并发读+写的场景下,依然数据库跟缓存不一致。

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

执行步骤

  1. 用户A查询缓存,缓存未命中
  2. 用户A查询数据库,得到值为:1
  3. 用户B更新数据库,值更新为:2
  4. 用户B删除缓存
  5. 用户A,把查询到的值1,回写到缓存

从结果看,缓存的是旧值:1,数据库是最新值:2,在并发读+写的场景下,依然数据库跟缓存不一致。

从理论上来分析,先更新数据,再删除缓存,依然存在数据库与缓存不一致的情况,但在实际中,出现不一致的情况概率非常低。

因为缓存的写入速度远远大于写入数据库的速度,为了以防万一,再给缓存数据加一个过期时间,如果真出现不一致的情况,也最多在过期时间的这个区间不一致,过期时间到了,重新更新缓存,也能到达最终一致性

方案选择

以下四种方案,我们都分析了,那我们到底用哪一种呢?

  1. 先更新数据库,再更新缓存
  2. 先更新缓存,再更新数据库
  3. 先更新数据库,再删除缓存
  4. 先删除缓存,再更新数据库

先说我的观点,也是大厂的方案,强烈推荐:先更新数据库,再删除缓存

原因如下

  1. 缓存的写入速度远远大于写入数据库的速度,出现不一致的的概率很低
  2. 设置过期时间,如果真出现不一致的情况,过期时间到期,重新刷新缓存,能达到最终一致性
  3. 正常的情况,缓存与数据强一致性,也没那么高的要求,如果真要达到强一致性,系统吞吐量必要下降

题外话:对于一致性的解决方案,我对大厂的方案很感兴趣,想了解他他们是怎么解决的。当进去后,深入了解下,使用的方案也是:先更新数据库,再删除缓存 ,最终一致性,没必要强一致性,原因跟上面三条差不多。

这样是不是很完美了嘛,等等,这种方案还有没有问题,想想…,看下图:

更新数据库,删除缓存是两个操作,如果删除缓存失败了呢(这种概率虽然很低),那缓存中依然是旧值,有没有什么方案解决这个问题呢?

上面的四种方案,无论是先操作数据库,还是操作缓存,都存在这种问题

问题原因知道了,该怎么解决呢?有两种方法:

  • 重试机制
  • 订阅 MySQL binlog,再操作缓存

如何保证两个操作都执行成功

重试机制

引入消息中间件,比如:rabbitmq

  • 如果应用删除缓存失败,发送消息到mq,然后从消息队列中重新读取数据,然后再次删除缓存,这个就是重试机制。当然,如果重试超过的一定次数,还是没有成功,我们就需要向业务层发送报错信息了。
  • 如果删除缓存成功,就要把数据从消息队列中移除,避免重复操作,否则就继续重试

订阅 MySQL binlog,再操作缓存

引入canal中间件

canal,译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费。

canal 工作原理

  • canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
  • MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
  • canal 解析 binary log 对象(原始为 byte 流)

所以,如果要想保证「先更新数据库,再删缓存」策略第二个操作能执行成功,我们可以使用「消息队列来重试缓存的删除」,或者「订阅 MySQL binlog 再操作缓存」,这两种方法有一个共同的特点,都是采用异步操作缓存,也可能存在短时间的不一致。

总结

如何保证数据库与缓存一致性?先更新数据库,再删缓存,缓存设置一个过期时间, 这种方案能适用95%以上的场景。

不知道你们在实际工作中,你们的项目,用的那种方案,踩过哪些坑,欢迎留言一起谈论。

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

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

相关文章

LangChain使用实例——RAG

Q&A with RAG Overview LLMs支持的最强大的应用程序之一是复杂的问答 (Q&A) 聊天机器人,这些应用程序可以回答有关特定源信息的问题,使用一种称为检索增强生成(RAG)的技术。 RAG RAG 是一种利用额外数据增强 LLM 知识…

linux 网卡配置 vlan/bond/bridge/macvlan/ipvlan 模式

linux 网卡模式 linux网卡支持非vlan模式、vlan模式、bond模式、bridge模式,macvlan模式、ipvlan模式等,下面介绍交换机端及服务器端配置示例。 前置要求: 准备一台物理交换机,以 H3C S5130 三层交换机为例准备一台物理服务器&…

如何用智能AI绘一幅世界地图?

今天我们分享一下,用智能AI绘一幅世界地图的方法! 为了方便你极速体验,特意在文末为你准备了登录帐号,省去你注册的烦恼。 认准AI绘画官网 如果你在百度搜索“AI绘画”或“Midjourney”,找出来的基本全是广告&#…

matplotlib画图:子图中坐标轴与标题重合...

如下图 只要在代码最后加入 plt.tight_layout() 就可以自动调节

Java练习题目6:水仙花数是指其个位,十位和百位三个数字的立方和等于其自身的三位数,求出所有的水仙花数。(Daddodil6)

每日小语 要相信卷首以卷尾为前提,几乎同卷尾以卷首为前提是一样的。——叔本华 思考 //水仙花数是指其个位,十位和百位三个数字的立方和等于其自身的三位数,求出所有的水仙花数。 import java.util.Scanner; public class Daddodil6 {publ…

服务运营 | 印第安纳大学翟成成:改变生活的水井选址

编者按: 作者于2023年4月在“Production and Operations Management”上发表的“Improving drinking water access and equity in rural Sub-Saharan Africa”探讨了欠发达地区水资源供应中的可达性和公平性问题。作者于2020年1月去往非洲埃塞俄比亚提格雷地区进行…

【Python进阶】:面向对象编程的力量:解锁封装、继承与多态的秘密武器

引言 在Python编程世界中,面向对象编程(Object-Oriented Programming, OOP)如同一把锋利的剑,它将现实世界的实体抽象为类,赋予程序更强的结构化、模块化特征,极大地提升了代码的可读性、可维护性和复用性…

抖音视频关键词批量采集工具|无水印视频爬虫提取软件

抖音视频关键词批量采集工具: 我们很高兴地介绍最新推出的抖音视频关键词批量采集工具,该工具集成了多项强大功能,让您轻松实现视频内容的批量提取和下载。以下是详细的功能解析和操作说明: 主要功能: 关键词批量提取…

如何使用PHP和RabbitMQ实现延迟队列(方式一)?

前言 今天我们来做个小试验,用PHP和RabbitMQ实现消息队列的延迟功能。 前期准备,需要安装好docker、docker-compose的运行环境。 需要安装RabbitMQ的可以看下面这篇文章。 如何使用PHP和RabbitMQ实现消息队列?-CSDN博客 一、安装RabbitM…

Python爬虫:爬虫基本概念、流程及https协议

本文目录: 一、爬虫的基本概念1.为什么要学习爬虫1.1 数据的来源1.2 爬取到的数据用途 2.什么是爬虫3. 爬虫的更多用途 二、爬虫的分类和爬虫的流程1.爬虫的分类2.爬虫的流程3.robots协议 三、爬虫http和https1.http和https的概念2.浏览器发送HTTP请求的过,2.1 http…

Tunes不能读取iPhone的内容,请前往iPhone偏好设置的摘要选项卡,然后单击恢复以将此iPhone恢复为出厂设置

重启itunes: 参考链接: https://baijiahao.baidu.com/s?id1642568736254330322&wfrspider&forpc 人工智能学习网站: https://chat.xutongbao.top

C++进阶--使用哈希表实现unordered_map和unordered_set的原理与实例

本文将介绍如何使用哈希表来实现C STL库中的unordered_map和unordered_set容器。我们将会解释哈希表的基本原理,并给出具体的代码示例,帮助读者更好地理解和应用哈希表。 哈希原理讲解–链接入口 set和map的实现的文章,与unordered_map实现类…

ros time 时间戳改为机器开机时间

文章目录 一、问题描述二、修改方法补充1. 时间类型2. 时间数据使用方法 一、问题描述 因项目需要,需要"ros::Time::now()" 改成获取机器开机时间,此处针对rospy的机器时间修改。 二、修改方法 修改ros源码的文件 /opt/ros/noetic/lib/python3/dist-packages/ros…

是德科技keysight DSOX3104A示波器

181/2461/8938产品概述: Keysight(原Agilent) InfiniiVision DSOX3104A 的价位较低,能够在满足您苛刻预算要求的情况下提供卓越性能,以及可选功能。是德(原安捷伦)突破性技术可以在相同的预算条件下提供更多更出色的示波器功能 Keysight(原A…

Navicat 干货 | 通过检查约束确保 PostgreSQL 的数据完整性

数据完整性对于任何数据库系统来说都是很重要的一方面,它确保存储的数据保持准确、一致且有意义的。在 PostgreSQL 中,维护数据完整性的一个强大工具是使用检查约束。这些约束允许你定义数据必须遵守的规则,以防止无效数据的插入或修改。本文…

[实战]Springboot与GB28181摄像头对接。摄像头注册上线(一)

与支持国标摄像头对接 前言:不想看教程?1、准备阶段1.1、我们会学到什么?1.2、创建项目1.3、pom中用到的依赖1.4 打开摄像头的网址(了解配置方式) 2、代码编写2.1、增加项目配置2.2、在config目录下创建SipConfig2.3、在service目录下创建Sip…

手机录屏在哪里找?手把手教你找到录屏功能

随着智能手机的普及和移动应用的快速发展,手机录屏功能变得越来越受欢迎。无论是记录游戏精彩瞬间、制作教程视频,还是为了保存重要的视频通话内容,手机录屏都能帮上大忙,可是很多人不知道手机录屏在哪里找,本文将介绍…

防静电检测设备如何完善PCBA车间的防静电管控?

在PCBA(Printed Circuit Board Assembly)车间中,静电是一个极其重要的问题,因为静电可能对电子元器件和PCB板造成损坏,进而影响整个生产流程和产品质量。为了有效防止静电问题,企业通常会引入防静电检测设备…

US-T65 DM蓝牙5.2双模热插拔PCB

键盘使用说明索引(均为出厂默认值) 一些常见问题解答(FAQ)注意首次使用步骤蓝牙配对(重要)蓝牙和USB切换键盘默认层默认触发层0的FN键配置的功能默认功能层1配置的功能默认的快捷键 蓝牙参数蓝牙MAC地址管理…

Win11电脑cpu温度过高怎么办呢

Win11电脑cpu温度过高怎么办呢?有时候我们感觉电脑发烫,担心电脑过烫会不会损坏。正常情况下,cpu的温度在45~65度之间,但不排除电脑同时开了太多软件,或者在玩吃鸡、英雄联盟等的大型游戏而导致温度超过85度。只要最高温不超过85度都仍在正常的波动范围。但是超过了,电脑…