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

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

欢迎加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.mzph.cn/news/773630.shtml

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

相关文章

锦城软件定义网络实验(只用于教学,第八周结束后自行删除)

一、实验环境简介: Ubuntu 20.0.4 Ryu/Opendaylightmininetsflow(网络监视技术)Apifox/postman(REST API流表控制工具) 二、软件定义网络知识图谱 三、SDN知识概述 1.SDN的三个主要特征: 网络开放可编程; 控制平面与数据平面分离…

云架构(二) 大使模式

Ambassador pattern (https://learn.microsoft.com/en-us/azure/architecture/patterns/ambassador) 简单描述 创建一个助手服务,这个服务代表消费服务或者应用程序发送网络请求。大使服务可以看做是与客户机同一个位置的进程外代理。 这种…

Web CSS笔记2

目录 1、背景 ①、背景图片(image) ②、背景平铺(repeat) ③、背景位置(position) ④、背景附着(attachment) ⑤、背景透明(CSS3) ⑥、背景图片缩放大小(size): ⑦、背景简写 2、标签显…

java智慧工地源码 大型建筑公司应用的智慧工地系统源码 智慧工地建筑管理系统源码

java智慧工地源码 大型建筑公司应用的智慧工地系统源码 智慧工地建筑管理系统源码 智慧工地是智慧地球理念在工程领域的具体体现,它代表了一种全新的工程全生命周期管理理念。通过运用信息化手段,智慧工地能够精确设计和模拟工程项目,实现互…

【高危漏洞】关于视频分片上传的漏洞修复

修改文件crmeb/app/services/system/attachment/SystemAttachmentServices.php 增加下方代码,将分片上传的第几片强制转成INT类型解决 $data[chunkNumber] (int)$data[chunkNumber];

linux命令-ln命令详解

文章目录 前言一、ln命令介绍1. 简介2. 硬链接2.1 inode介绍 3. 软连接(符号链接)4. 语法5. 选项和参数 二、示例用法1. 创建硬链接2. 创建软链接2.1 给文件创建软链接2.2 给目录创建软链接 总结 前言 本文介绍了ln命令的用法和特点,包括硬链…

【TypeScript】解决字面量类型推断错误的四种方式

解决字面量类型推断错误的四种方式 方式一:对象属性使用类型断言方式二:传参使用类型断言方式三:对象使用类型断言方式四:对象属性使用变量,变量使用字面量类型参考 declare function handleRequest(url: string, meth…

[蓝桥杯 2022 省 A] 求和

[蓝桥杯 2022 省 A] 求和 题目描述 给定 n n n 个整数 a 1 , a 2 , ⋯ , a n a_{1}, a_{2}, \cdots, a_{n} a1​,a2​,⋯,an​, 求它们两两相乘再相加的和,即 S a 1 ⋅ a 2 a 1 ⋅ a 3 ⋯ a 1 ⋅ a n a 2 ⋅ a 3 ⋯ a n − 2 ⋅ a n − 1 a n − 2 ⋅ a…

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

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

AD域---共享文件夹-容量配额管理

域环境共享文件夹-容量配额管理 要求 1/李斯用户配额10G云盘空间,张珊用户配额30G云盘空间 2/D:\ 配额-启用配额-启用配额管理-拒绝将磁盘空间给超过配额限制的用户-勾选 3/将磁盘空间限制为:55GB,将警告等级设为50GB 4/选择该卷的配额记录选项-勾选…

大型集团公司企业文化知识竞活动赛策划方案

一场高端企业文化知识竞赛活动完整策划书,按诗词大会舞美标准进行设计,竞赛规则新颖,值得收藏。 天纵高端知识竞赛服务商,20多年现场经验和软硬件开发。 专业承办全国高端知识竞赛活动。线上线下各类竞赛活动均可执行,…

鸿蒙开发之了解ArkTS

鸿蒙开发者官网 : https://developer.huawei.com/consumer/cn/ 开发鸿蒙要用的软件是 DevEco Studio ArkTS建立在JS和TS的基础之上,扩展了声明式UI开发范式和状态管理,提供更简洁和自然的开发方式。 ArkTS引入了渲染引擎的增强&#xff0c…

04. 【Android教程】Android 工程解析及使用

在上一章中已经搭建好了 Android 开发环境,本章我们将一起通过 Eclipse 创建我们的第一个 Android App。 1. 创建 Android 工程 首先打开 Eclipse,在菜单栏依次选择“New” -> “Android App Project”。如果是第一次创建,可能没有“Andr…

ChatGPT,来一份3·28雷布斯米时捷上市发布会即时发言稿

你新招了一个秘书。上班第一天,你对他说:“3月28号我可能会受邀参加雷老板的米时捷’上市发布会,届时我可能会有十分钟的发言机会,你现在准备一篇演讲稿。” 秘书问你有何指导意见? 你自己都不知说啥子,能…

gcc任意版本安装流程(linux)

一.更换镜像源 仅仅针对有需要换镜像需求的用户 sudo gedit /etc/apt/sources.list 用于在基于Debian的Linux发行版(如Ubuntu)上用来编辑软件源列表的命令。 我们更换阿里源: deb http://mirrors.aliyun.com/ubuntu/ focal main restricted…

fl studio21.2中文版下载及使用基础教学

FL Studio 21.2.2是一款功能强大的音乐制作软件,也被广大用户称为“水果编曲”。这款软件支持简体中文和英语,适用于Windows 10/11(仅限64位)以及MacOS 10.13.6或更高版本的系统。 在FL Studio 21.2.2中,用户可以享受…

AI论文速读 | 【综述】用于轨迹数据管理和挖掘的深度学习:综述与展望

论文标题:Deep Learning for Trajectory Data Management and Mining: A Survey and Beyond 作者:Wei Chen(陈伟), Yuxuan Liang(梁宇轩), Yuanshao Zhu, Yanchuan Chang, Kang Luo, Haomin Wen(温皓珉), Lei Li, Yanwei Yu(于彦伟), Qingsong Wen(文青…

【PADS 原理图Logic发送网表元器件丢失的解决办法】

1、PADS版本:VX1.2 2、PADS Logic原理图导入PCB Layout后,发现总有几个元器件怎么导都不会显示在PADS Layout上,如下图: PADS Logic上也选择了封装,还是不行,如下图: 3、解决办法: …

深入了解 Postman 请求头的使用方法

当你在使用 Postman 发送请求时,请求头(Headers)是你可以包含在 HTTP 请求中的重要部分之一。请求头包含了关于请求的元数据信息,这些信息对于服务器来处理请求是非常重要的。下面是一份详细的图文介绍,说明了如何在 P…

电源模块 YULIN俞霖科技DC/DC电源模块 直流升压 高压稳压

Features 最低工作电压:0.7V电压隔离:1000VDC /3000VDC 平均无故障时间: > 800,000 小时短路与电弧保护无最低负载要求:可空载工作输入电压:5、12、15、24VDCOutput 100,200、300、400、500 、600、800、 1000、1…