十六、Redis和数据库双写一致性问题

news2024/12/27 16:22:44
众所周知,Redis一般被用来做为数据的缓存中间件,提升系统读数据的能力。但是被缓存的数据并不是一成不变的。如果是永远不会变的,那不会存在双写一致性问题(只需构建一次缓存即可)。但是大部分情况下,或多或少都会涉及到缓存数据的变更的问题。这时就需要思考一个问题,到底是先操作数据库,还是先操作缓存。

image.png

1、先更新数据库,在更新缓存

这套方案是最被大家反对的方案。有以下几点原因:
原因一、同时有请求A和请求B进行更新操作,那么会出现

  1. 线程A更新了数据库
  2. 线程B更新了数据库
  3. 线程B更新了缓存
  4. 线程A更新了缓存

这就出现请求A更新缓存应该比请求B更新缓存早,但是因为某种原因,B的更新却比A的更新早。这就造成了缓存中的脏数据出现。

2、先删缓存,在更新数据库

改方案导致不一致的原因是:同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么就会出现以下情形:

  1. 请求A删除缓存
  2. 请求B查询,发现缓存中不存在
  3. 请求B去查询数据库得到旧值
  4. 请求B将旧值写入缓存
  5. 请求A将新值写入到数据库

上面就会出现数据不一致问题,即使请求A先删掉缓存,这是请求B在A更新数据库前请求,就会出现又将旧值写到缓存的问题。就会导致数据库和缓存不一致的问题。
对于上面的问题,可以采用延时双删的策略。

redis.deleteKey(key)
db.update
Thread.sleep(500)
redis.deleteKey(key)
其实就是:
  1. 先删除缓存
  2. 更新数据库
  3. 休眠一段时间,在删除缓存。(允许在睡眠这段时间内的脏数据)

针对上面的情景,睡眠的时间应该根据自己的业务来进行判断,写数据的休眠时间应该在读数据的耗时基础上加上个几百毫秒即可。这样做的目的可以确保读请求结束后,写请求可以删除读请求造成的缓存脏数据。

但是如果是使用的mysql的读写分离架构怎么办?
那么在这种情况下,造成数据不一致的原因如下:

  1. 请求A写操作,删除缓存
  2. 请求A将数据写入主数据库
  3. 请求B查询缓存,发现不存在
  4. 请求B去从库查询得到旧值
  5. 请求B将旧值写到缓存
  6. 数据库完成主从同步,从库变为新值

上面这种情形,就是造成数据不一致的原因。请求B在主从同步之前,来请求这是还会将旧值写到缓存中,即使A请求删除掉了缓存。
还是使用延时双删策略。只是睡眠时间修改为在主从同步的延时时间上增加几百毫秒。

但是采用延时双删策略,会降低系统的吞吐量。
对于这个问题,可以将第二次删除采用异步的方式。这样写请求就不用睡眠一段时间在返回。

但是如果,第二次删除失败了会怎么样?
当请求A去删除请求B读取的旧值写到的缓存时失败,这是又会出现,缓存和数据库不一致的情况。这种情况就看下第三种更新策略。

3、先更新数据库,在删缓存

其实这种情况也存在并发问题。
假设有两个请求,一个请求A做查询请求,另一个请求B做更新请求,那么会有如下情况产生:

  1. 缓存刚好失效
  2. 请求A查询数据库,得到一个旧值
  3. 请求B将新值写入数据库
  4. 请求B删除缓存
  5. 请求A将查询的旧值更新到缓存

这种情形也会发生脏数据。
但是这种情形发生的概率是极低的。

发生上述情况的前提条件是步骤3的写数据操作比步骤2的查询操作耗时更短(只有这样才能在请求B在请求A之后写库,但是比A先执行完)。
但是一般来说,写的请求耗时是比读的请求更多的。总的来说这种情形很少出现。

但是假设如果一定会出现这种情形呢!如何处理呢?
首先,给缓存设置一个过期时间是一个有效的解决方案。另外也可以采用策略2中提到的延时双删策略。但是这个方法也会出现第二次删除失败的问题。回导致数据的不一致。

对于解决上述问题的方法,可以采用提供一个保障的重试机制方法。

方案一:采用失败发送MQ消息队列的方式,重试机制。
image.png
方案二:采用订阅数据库的binlog日志的方式
image.png

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

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

相关文章

发布一下之前的草稿和仅我可见【个人】

发布一下之前的草稿和仅我可见【个人】 前言版权推荐发布一下之前的草稿和仅我可见【个人】java面试面试真题笔试真题 最后 前言 2024-5-13 12:26:55 发布一下之前的草稿和仅我可见 这些一般多事和面试相关的内容 以下内容源自《【创作模板】》 仅供学习交流使用 版权 禁止…

禅道远程安装配置(cpolar)

1. 禅道安装 2. cpolar下载安装 Cpolar的下载可以直接登录cpolar官网(www.cpolar.com),下载对应版本即可 download下载 - cpolar 极点云官网 2.1 cpolar官网注册账号 2.2 macOS可以通过brew安装 Cpolar快速入门教程:macOS系列…

16-LINUX--线程安全

一。线程安全 线程安全即就是在多线程运行的时候,不论线程的调度顺序怎样,最终的结果都是 一样的、正确的。那么就说这些线程是安全的。 要保证线程安全需要做到: 1) 对线程同步,保证同一时刻只有一个线程访问临界资…

软件3班20240513

java.util.PropertyResourceBundle4554617c package com.yanyu;import java.sql.*; import java.util.ResourceBundle;public class JDBCTest01 {public static void main(String[] args) throws SQLException { // 获取属性配置文件ResourceBundle bundle Res…

【NodeMCU实时天气时钟温湿度项目 3】连接SHT30传感器,获取并显示当前环境温湿度数据(I2C)

今天,我们开始第三个专题:连接SHT30温湿度传感器模块,获取当前环境实时温湿度数据,并显示在1.3寸TFT液晶显示屏上。 第一专题内容,请参考 【NodeMCU实时天气时钟温湿度项目 1】连接点亮SPI-TFT屏幕和UI布局设计…

8个手机宝藏App,建议收藏!

AI故事视频生成,一站式生成小说漫画推文、儿童故事、民间故事等https://aitools.jurilu.com/ 1.地图车机版——百度地图 百度地图,作为新一代的人工智能地图,以其智能语音、智能导航系统、智能路线规划和智能推荐方案而著称。它不仅提供传统…

spring bean生命周期全部过程

Spring Bean的生命周期包括以下全部过程: 实例化:在Spring容器启动时,根据配置文件或注解等信息创建Bean的实例。属性赋值:如果Bean有属性需要进行初始化,Spring容器会自动为这些属性进行赋值。自定义初始化方法&…

【网站项目】SpringBoot792考试系统

🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板&#xff…

css 步骤条虚线渐变色效果实现

效果如图所示&#xff1a; 思路&#xff1a; 使用元素覆盖的方式实现视觉上虚线的效果 实现代码&#xff1a; html布局 <ul class"details-cont"><li class"details-li" v-for"item in 3" :key"item"><div class&qu…

C/C++开发工具CLion全新发布v2024.1——提升CMake编辑体验

CLion是一款专为开发C及C所设计的跨平台IDE。它是以IntelliJ为基础设计的&#xff0c;包含了许多智能功能来提高开发人员的生产力。这种强大的IDE帮助开发人员在Linux、OS X和Windows上来开发C/C&#xff0c;同时它还使用智能编辑器来提高代码质量、自动代码重构并且深度整合CM…

多模态产品在智能文档处理应用的展望------以TextIn模型为例

前言发展现状TextIn 文档解析技术文本向量化展望合合信息 前言 第十四届视觉与学习青年学者研讨会(VALSE 2024)于5月5日-7日在山城重庆渝北区悦来国际会议中心举办。大会聚焦计算机视觉、模式识别、多媒体和机器学习等领域的国际前沿和热点方向。大会中&#xff0c;合合信息智能…

企业信息系统的总体框架

1.信息系统体系结构的总体参考框架 信息系统的架构&#xff08;Information System Architecture&#xff0c;ISA&#xff09;中的Architecture含义具有丰富内涵和作用&#xff0c;相比计算机领域的Architecture来说它的单一性、片面性模型是难以描述ISA的全部的&#xff0c;IS…

【SAP-FICO】SAP-FICO生产订单-结算规则配置路径(OKO7)

需求&#xff1a; 作为一个ABAPer&#xff0c;有接到一个狗屁倒灶的配置需求&#xff0c;要求如下&#xff0c;给生产订单的结算规则显示出来 图1&#xff1a;找一个生产订单&#xff0c;显示其结算规则 CO03→菜单栏-表头→结算规则 图2&#xff1a;查看该生产订单&#xff0c…

仿TCMalloc高并发内存池项目介绍

TCMalloc项目介绍 TCMalloc介绍 Thread-Caching Malloc&#xff08;TCMalloc&#xff09;&#xff0c;即线程缓存的malloc&#xff0c;是一种高性能的内存分配器&#xff0c;由Google开发并作为gperftools项目的一部分。TCMalloc旨在提高多线程程序的内存分配性能&#xff0c;通…

smardaten让原型不仅只有原型!

smardaten面向软件研发全流程&#xff0c;从设计、开发、测试、到运维人员均可以基于平台完成一体化的开发工作。 随着平台设计场景下功能与组件的不断完善&#xff0c;在面对招投标、售前演示、需求确认的诉求时&#xff0c;已经有不少企业将软件原型设计的主战场转移至smard…

【进程替换】自定义程序替换 | 替换函数execleexecvpe | execve

目录 自定义程序替换 Makefile mypragma.cc☞mypragma testexec.c☞testexec test.py&test.sh execle&execvpe 1.自定义 testexec.c☞testexec mypragma.cc☞mypragma 2.系统 3.系统修改putenv execve 替换函数总结 自定义程序替换 前面我们举例进程程…

PythonStudio 控件使用常用方式(十一)MessageBox

PythonStudio是一个极强的开发Python的IDE工具&#xff0c;它使用的是Delphi的控件&#xff0c;常用的内容是与Delphi一致的。但是相关文档并一定完整。现在我试试能否逐步把它的控件常用用法写一点点&#xff0c;也作为PythonStudio的参考。 MessageBox是一个消息对话框&…

docker八大架构之应用服务集群架构

应用服务集群架构 在之前&#xff0c;一个应用层要负责所有的用户操作&#xff0c;但是有时用户增加后就会导致供不应求的现象&#xff08;单个应用不足以支持海量的并发请求&#xff0c;高并发的时候站点响应变慢&#xff09;&#xff0c;这时就需要增加应用层服务器&#xf…

报表-设计器的使用

1、设计器目录结构 报表设计器以压缩包的方式提供&#xff0c;解压后&#xff0c;目录结构如下&#xff1a; 目录说明&#xff1a; 1、jdk-17&#xff1a;压缩包中自带的windows平台下的jdk17 2、lite-report&#xff1a;报表文件和数据源配置文件的保存位置 3、lite-repor…

无人售货机零售项目ECharts展现(最全!!,文档放最后哦!)

目录 背景 数据表 框架分析 可视化展示销售情况总分析 1、绘制仪表盘展示各特征及其环比增长率&#xff08;仪表盘&#xff09; 1. 销售金额及其环比增长率 2. 订单量及其环比增长率 3. 毛利率及其环比增长率 4.售货机数量及其环比增长率 2、绘制簇状柱状-折线图展示…