Redis缓存一致性问题及解决方案

news2024/11/25 20:23:16

对于没有并发的用户请求

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

两者第二步没成功,都有问题

  • 如果更新缓存成功,更新数据库没成功,一旦缓存失效,读取的仍是旧值
  • 如果更新数据库成功,更新缓存没成功,则修改结果迟迟看不到

然后就是两者都有并发的情况下:

先更新缓存后更新数据库

  • 用户A更新缓存x=2(x=1)
  • 用户B更新缓存x=1
  • 用户B写入数据库x=1
  • 用户A写入数据库x=2

用户A把用户B的请求覆盖了

先更新数据库后更新缓存

  • 线程 A 更新数据库(X = 1)
  • 线程 B 更新数据库(X = 2)
  • 线程 B 更新缓存(X = 2)
  • 线程 A 更新缓存(X = 1)

线程A的缓存把线程B的缓存覆盖了

显然有问题,以上是并发问题,除此之外从缓存利用率来讲,更新的缓存不一定会马上被读取,可能会导致缓存中有很多没有用的数据,浪费资源。

解决方案:删除缓存

  • 先删除缓存,再更新数据库
  1. 线程 A 要更新 X = 2(原值 X = 1)
  2. 线程 A 先删除缓存
  3. 线程 B 读缓存,发现不存在,从数据库中读取到旧值(X = 1)
  4. 线程 A 将新值写入数据库(X = 2)
  5. 线程 B 将旧值写入缓存(X = 1)

最终 X 的值在缓存中是 1(旧值),在数据库中是 2(新值),发生不一致。

  • 先更新数据库,再删除缓存
  1. 缓存中 X 不存在(数据库 X = 1)
  2. 线程 A 读取数据库,得到旧值(X = 1)
  3. 线程 B 更新数据库(X = 2)
  4. 线程 B 删除缓存
  5. 线程 A 将旧值写入缓存(X = 1)

最终 X 的值在缓存中是 1(旧值),在数据库中是 2(新值),也发生不一致。

然而上述条件很难满足,特别是条件三

  • 缓存刚好已失效
  • 读请求 + 写请求并发
  • 更新数据库 + 删除缓存的时间(步骤 3-4),要比读数据库 + 写缓存时间(步骤 2 和 5)

如何保证两步都执行成功

程序在执行过程中发生异常,最简单的解决办法是什么?

重试

直接重试方案不严谨:

异步重试

把重试请求写到「消息队列」中,然后由专门的消费者来重试,直到成功

或者更直接的做法,为了避免第二步执行失败,我们可以把操作缓存这一步,直接放到消息队列中,由消费者来操作缓存。

问题:

如果在执行失败的线程中一直重试,还没等执行成功,此时如果项目「重启」了,那这次重试请求也就「丢失」了,那这条数据就一直不一致了

解决方法:消息队列特性

  • 消息队列保证可靠性:写到队列中的消息,成功消费之前不会丢失(重启项目也不担心)
  • 消息队列保证消息成功投递:下游从队列拉取消息,成功消费后才会删除消息,否则还会继续投递消息给消费者(符合我们重试的场景)

至于写队列失败消息队列的维护成本问题:

  • 写队列失败:操作缓存和写消息队列,「同时失败」的概率其实是很小的
  • 维护成本:我们项目中一般都会用到消息队列,维护成本并没有新增很多

在这里插入图片描述

更简单的方案

订阅数据库变更日志,再操作缓存

们的业务应用在修改数据时,「只需」修改数据库,无需操作缓存。

当一条数据发生修改时,MySQL 就会产生一条变更日志(Binlog),我们可以订阅这个日志,拿到具体操作的数据,然后再根据这条数据,去删除对应的缓存

在这里插入图片描述

订阅变更日志,目前也有了比较成熟的开源中间件,例如阿里的 canal,使用这种方案的优点在于:

  • 无需考虑写消息队列失败情况:只要写 MySQL 成功,Binlog 肯定会有
  • 自动投递到下游队列:canal 自动把数据库变更日志「投递」给下游的消息队列

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

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

相关文章

MySQL官网下载Linux版本安装包

步骤一:https://www.mysql.com/ 步骤二:https://www.mysql.com/downloads/ 步骤三:https://dev.mysql.com/downloads/ 步骤四:https://dev.mysql.com/downloads/mysql/

二十分钟秒懂:实现前后端分离开发(vue+element+spring boot+mybatis+MySQL)

目录 开发者介绍 什么是前后端分离开发 vue与springboot开发的优势 Vue.js 的优势: Spring Boot 的优势: vue与springboot如何实现前后端连接 demo简介 重要部分前端部分代码 重要部分后端代码 后端解决跨域问题 Controller部分 xml部分 se…

商城APP开发需要哪些功能,如何选择开发公司

商城APP开发的功能有很多,从功能上看主要分为以下几个大类: 一、商品展示类:商家可以在这里展示自己产品的种类、数量、价格等信息,消费者在浏览和选择的时候,能直观的看到商家介绍。 二、优惠促销类:商家…

JDBC与DBCP整合

DBCP:DataBase Connection Pool,数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接…

第四章 相似矩阵与矩阵对角化

引言 题型总结中推荐例题有蓝皮书的题型较为重要,只有吉米多维奇的题型次之。码字不易,如果这篇文章对您有帮助的话,希望您能点赞、评论、收藏,投币、转发、关注。您的鼓励就是我前进的动力! 知识点思维导图 补充&…

【Web服务器集群】Apache配置与应用

文章目录 一、构建虚拟web主机1.概述2.httpd服务支持的虚拟主机类型3.构建虚拟Web主机3.1基于域名的虚拟主机3.2基于IP地址的虚拟主机3.3基于端口的虚拟主机 4.Apache连接保持5.Apache访问控制 二、Apache日志管理rotatelogs分隔工具 三、总结1.Web虚拟主机部署步骤2.网页根目录…

DN-DETR代码学习笔记

代码地址:GitHub - IDEA-Research/DN-DETR: [CVPR 2022 Oral]Official implementation of DN-DETR 论文地址: https://arxiv.org/pdf/2203.01305.pdf DN-DETR是在DAB-DETR的基础上完成的,DN-DETR的作者认为导致DETR类模型收敛慢的原因在于匈牙…

【Linux升级之路】4_进程控制

文章目录 前言一、【Linux初阶】fork进程创建 & 进程终止 & 进程等待二、【Linux初阶】进程程序替换 | 初识、原理、函数、应用 & makefile工具的多文件编译三、【Linux初阶】进程替换的应用 - 简易命令行解释器的实现结语 前言 本片博客是 Linux操作系统 进程控制…

【周末闲谈】谈谈数学转码这一年来的体会与反思

——我们走了太远,以至于忘了为何出发 前言 笔者本科读的是数学专业,就是每天和数学分析、高等代数、概率论、随机过程等等这些理论打交道的专业,这个专业出来工作好像一般有两个方向就是金融和计算机,我选择了计算机方向。主要…

【自然语言处理】【大模型】ChatGLM-6B模型结构代码解析(单机版)

ChatGLM-6B模型结构代码解析(单机版) ​ 本文介绍ChatGLM-6B的模型结构,代码来自https://huggingface.co/THUDM/chatglm-6b/blob/main/modeling_chatglm.py。 相关博客 【自然语言处理】【大模型】ChatGLM-6B模型结构代码解析(单机版) 【自然语言处理】【大模型】BL…

日撸 Java 三百行day56-57

文章目录 day56-57 kMeans 聚类1.kMeans聚类理解2.代码理解2.1代码中变量的理解2.2代码理解 day56-57 kMeans 聚类 1.kMeans聚类理解 无监督的机器学习算法,其中k是划分为几个簇,并且选择k个数据作为不同簇的聚类中心,计算每个数据样本和聚…

ASRT语音识别系统的部署以及模型的使用(运用篇)

ASRT语音识别系统的部署以及模型的使用(运用篇) 前言 ASRT是一个中文语音识别系统,由AI柠檬博主开源在GitHub上。 GitHub地址:ASRT_SpeechRecognition 国内Gitee镜像地址:ASRT_SpeechRecognition 文档地址:ASRT语音识别工具文…

Python打包成EXE

一、使用Pyinstaller pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller 1.2Pyinstaller打包步骤 Pyinstaller -F -w -i apple.ico py_word.py 结果: 运行结果: 二、使用Auto-py-to-exe auto-py-to-exe 是一个用于打包 python 程序…

第二届(2023年)中国国际培育钻石产业发展与创新大会盛大召开!

5月25-26日,由广东省商务厅、中国国际贸易促进委员会广东省委员会(广东国际商会)、广州市商务局、番禺区人民政府、广东省交易控股集团有限公司/广东省公共资源交易中心指导,广州钻石交易中心(简称广钻中心&#xff09…

C语言深度解析--指针

目录 指针 指针的定义: 指针的大小: 指针和指针类型 野指针 指针运算 指针-整数: 指针-指针: 指针的关系运算: 指针和数组 二级指针 指针数组 理解指针的第一步是在机器级上观察指针表示的内容。大多数现代…

第十六届全国大学生信息安全竞赛创新实践赛初赛部分WP AGCTF战队

持续两天的比赛,打的很累,web没有出太多的题,比赛被pwn师傅带飞了,希望下此加油,下边是此次比赛排名。 文章目录 MISC签到卡被加密的生产流量国粹调查问卷pyshell CRYPTO基于国密SM2算法的密钥密文分发可信度量Sign_i…

Java中的深拷贝和浅拷贝介绍

文章目录 基本类型和引用类型Clone方法浅拷贝深拷贝小结 在讲解什么是深拷贝和浅拷贝之前,我们先来了解一下什么是基本类型和引用类型。 基本类型和引用类型 基本类型也称为值类型,分别是字符类型 char,布尔类型 boolean以及数值类型 byte、…

Vue3 项目相关

vite 项目起步式 npm create vite - 1.命名项目名称- 2. 选择技术框架- 3. 进入项目文件夹 npm i 安装依赖,- 4. npm run dev 运行项目配置 package.json 文件 ,使项目运行后自动再浏览器中打开。 在 dev 运行命令后添加一个 --open 即可。 "script…

微信小程序初识

微信小程序 因(ios,android)多平台彼此间并不互通,所以开发需要两个不同平台的开发团推队,所以微信小程序因此诞生。 小程序的优点 快速加载更强大的能力原生的体验易用且安全的微信数据开放高效和简单的开发 首先 根据自己的情况安装微…

弄懂软件测试左移和右移,靠它就行

软件测试技术应当贯穿整个软件开发生命周期、对软件产品(包括阶段性产品)进行验证和确认的活动过程,其核心目标是尽快尽早地发现软件产品中所存在的各种问题 bug—— 与用户需求、预先定义的不一致性。 传统的软件测试流程是 接到项目后参与…