如何保证Redis的缓存和数据库中的数据的一致性?

Redis的缓存如何和数据库中的数据保持一致性?

我们都知道,Redis是一个基于内存的键值存储系统,数据完全存放在内存中,这使得它的读写速度远超传统的硬盘存储数据库。对于高访问频率、低修改率的数据,通过将它们缓存在Redis中,应用可以快速地从内存中获取数据,能够大量减少数据库的查询次数,特别是在高并发场景下,有效避免了数据库可能成为整个系统的瓶颈问题。

🍭 但是在实际开发情景中,我们如何才能保证Redis缓存中的数据和数据库中数据的一致性呢?

什么情况会出现数据的不一致?

MySQL和Redis的操作包括读操作和写操作两种,那么有哪些情况是会导致二者数据不一致的?我们先从读和写的操作流程看起~

使用Redis读取数据的场景

在这里插入图片描述
🔆使用Redis读取数据的场景

  • 客户端发起一个查询数据的接口;
  • 向Redis中查询是否存在该条数据
    • 如果存在则直接返回;
    • 不存在则向数据库中查询,再将数据库中的数据保存在Redis中,然后设置一个过期时间,之后再返回客户端。

💡 设置过期时间的主要作用就是为了保证一些冷数据过期自动淘汰,不至于一直存在Redis中占用空间

使用Redis写数据的场景

🔆对数据进行修改是分为两个步骤:

  • 修改数据库数据
  • 修改/删除Redis缓存

为什么不推荐更新缓存而是直接删除?

删除逻辑非常简单,只需要在下一个线程的时候查询Redis,查询不到再从数据库中加载即可,其副作用只是增加了一次chache miss;而更新缓存的成本更高,因为我们写入数据库的值,很多情况下并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么每次写入数据库后,都要再次计算写入缓存的值,无疑是浪费性能,显然直接删除缓存更为合适,推荐直接删除。

🍭那么接下来的问题就是先操作缓存还是先操作数据库了

先操作缓存

在这里插入图片描述

🔆先操作缓存即先将缓存清空,再对数据库数据进行修改

  • 线程一进行删除Redis缓存和修改数据库数据操作,线程二进行查询数据操作
  • 线程一将Redis缓存清空之后发生了网络延迟,此时线程二进行缓存读取
  • 线程二在Redis缓存中查询不到数据,向数据库中查询数据并将查询到的数据加载到Redis缓存中,此时Redis缓存中存储的还是原先的老数据
  • 线程一完成数据的修改操作
  • 此时数据库中的数据是修改后的新数据,而Redis缓存中的数据还是更新前的旧数据,此时就发生了Redis缓存和数据库中的数据不一致的情况

💡 如果先操作Redis缓存的话,就可能出现将Redis中的数据删除之后旧数据又被放入其中去,如果后期再有查询操作,那么在Redis缓存中查询到的数据就会全部是旧的数据,产生了缓存脏读,直到数据到了过期时间被清除掉,如果没有设置过期时间该数据就永远都是脏数据,不能保证Redis和数据库的一致性

先操作数据库

那我们先操作数据库呢?还会有这种问题的发生吗?
在这里插入图片描述

🔆先进行数据库操作流程

  • 线程一进行删除Redis缓存和修改数据库数据操作,线程二进行查询数据操作
  • 线程一首先对数据库中的数据进行修改
  • 在此期间如果出现了另外一个线程来查询数据,就会直接从Redis中读取旧数据返回
  • 线程一操作完数据库后对Redis缓存进行延迟删除
  • 接下来的查询操作在Redis中查询不到数据,会向数据库中查询,并将查询到的数据放入Redis缓存中,此时Redis和数据库中的数据都是修改后的新数据

💡 先删数据库再删缓存,在多线程的情况下,当一个线程删除数据库,另一个线程读取缓存数据,读到的是未修改的Redis缓存中的旧数据,当先前一个线程删除完数据库后就会更新缓存,此时Redis和数据库中的数据就可以一致了,只会产生一次脏读

如何保证数据的一致性

🍭此时我们可以看到,在只读场景中是不会出现数据不一致的情况的,只有在并发的写操作中才会出现。问题已经很清楚了,那么如何解决呢?

强一致性和弱一致性

🔆首先我们先来了解两个概念:强一致性和弱一致性:

  • 强一致性:任何一次读都能读到某个数据的最近一次写的数据;
  • 弱一致性:数据更新后,如果能容忍后续的访问,只能访问到部分或全部访问不到;

延时双删策略

如果我们先操作Redis再操作数据库的话,就会出现我们上面所说到的脏读的问题,要解决这个问题,我们可以使用延迟双删的策略:在更新MySQL之后,等待一个短时间(例如几秒)再尝试第二次删除,防止在这段时间内有请求重建缓存而造成数据不一致。

基于消息队列

使用消息队列(如RabbitMQ、Kafka等)异步处理数据更新,更新MySQL的同时将更新事件发送到队列,消费者收到消息后负责更新Redis缓存。

订阅MySQL binlog同步

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

删除重试机制

使用删除重试机制,保证删除缓存成功。比如重试三次,三次都失败则记录日志到数据库并发送警告让人工介入。在高并发的场景下,重试最好使用异步方式,比如发送消息到mq中间件,实现异步解耦。

🏮以上的这些方法最多只能实现弱一致性🏮,也就是不能保证更新后每次读取到的数据都是最新数据,如果我们想要保证每次查询到的数据都是新的数据的话,即保证数据的强一致性,那就必须要保证他们的操作是原子性的,那么只能加一把锁了。但是加锁的话是会影响到系统的吞吐量,而我们使用Redis就是为了提高性能,如果为了保证数据的强一致性而加一把锁,那么就得不偿失了。

总结

  • 数据不一致的情况在只读场景中是不会出现的,只有在并发的写操作中才会出现;
  • 相对于直接删除Redis缓存来讲,修改缓存的成本更高,因此更加推荐修改数据库后直接删除Redis缓存,在下一次查询操作时再向数据库中拿到数据保存在Redis中;
  • 先操作Redis的话为了保证和数据库数据的最终一致性,需要进行延时双删的操作,即对Redis缓存进行两次删除,相比于先操作MySQL来说多进行一次删除Redis的操作;
  • 无论是先操作数据库还是先操作缓存,都会出现脏读的情况,因为redis和数据库不是原子性的,要想保证其原子性那么只有加锁,但是加锁的话又会影响性能;
  • Redis删除失败要进行重删操作

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

动态规划:线性dp

1.最长公共子序列(LCS) dp[i][j]含义:序列Ai(a1-ai)和Bj(b1-bj)的最长公共子序列长度 分析两种情况: (1)当ai bj时,已经求得Ai-1和Bj-1的最长公共子序列 dp[i][j] dp[i-1][j-1] 1 (2)当…

C++:比较运算符(18)

就是进行数据的比较&#xff0c;表达式正确的话就是真&#xff0c;错的话就是假&#xff0c;真假则由bool值来代替&#xff0c;非0即真 等于&#xff08;为赋值&#xff0c;为比较&#xff09;10 200!不等于10 ! 201>大于10 > 200<小于10 < 201>大于等于20 >…

windows安装Openssl

openssl官网:[ Downloads ] - /source/index.html Windows 安装方法 OpenSSL 官网没有提供 Windows 版本的安装包&#xff0c;可以选择其他开源平台提供的工具 Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 等待下载完成 捐不起 配置环境变量 ope…

【图论】【基环内向树】【广度优先】【深度优先】2127. 参加会议的最多员工数

作者推荐 视频算法专题 本文涉及知识点 图论 基环内向树 LeetCode2127. 参加会议的最多员工数 一个公司准备组织一场会议&#xff0c;邀请名单上有 n 位员工。公司准备了一张 圆形 的桌子&#xff0c;可以坐下 任意数目 的员工。 员工编号为 0 到 n - 1 。每位员工都有一位…

XML --java学习笔记

XML(全称EXtensible Markup Language&#xff0c;可扩展标记语言) 本质是一种数据的格式&#xff0c;可以用来存储复杂的数据结构&#xff0c;和数据关系 XML的特点 XML中的“<标签名>”称为一个标签或一个元素&#xff0c;一般是成对出现的XML中的标签名可以自己定义…

数字信号处理实验---FFT分析

一、题目&#xff1a; 二、实验要求&#xff1a; 1、绘制图形时&#xff0c;尽量选用已经提供的函数。 2、所有的图形&#xff0c;需要加上横坐标、纵坐标以及标题的说明。 3、将设计的程序保存为脚本文件&#xff0c;在实验报告中&#xff0c;需写出程序语句。 4、Matlab程…

【GlobalMapper精品教程】073:像素到点(Pixels-to-Points)从无人机图像轻松生成点云

文章目录 一、工具介绍二、生成点云三、生成正射四、生成3D模型五、注意事项一、工具介绍 Global Mapper v19引入的新的像素到点工具使用摄影测量原理,从重叠图像生成高密度点云、正射影像及三维模型。它使LiDAR模块成为已经功能很强大的的必备Global Mapper扩展功能。 打开…

安装geopandas很简单。。。

创建新环境 创建新环境并不是绝对必要的&#xff0c;但考虑到安装来自不同通道的其他地理空间包可能会导致依赖冲突 &#xff0c;安装新环境可能是很好的做法&#xff0c;在干净的环境中堆叠&#xff0c;重新开始。 以下命令创建一个名为geo_env的新环境&#xff0c; 将其配置…

CANoe之使用以及车载项目实操总结

以下是我通过8年的项目实操自我总结的一些经验和技术&#xff0c;作为一名奋斗在一线的研发人员&#xff0c;无时无刻不在做自我总结&#xff0c;所有的总结都是通过日报、周报、月报提炼出来的&#xff0c;实践是检验技术的唯一标准&#xff1b; 欢迎大家的交流和分享 思维导…

VSCODE使用VSIX安装扩展

VSCode安装扩展特别慢&#xff0c;使用命令行安装告别龟速&#xff1a; code --install-extension当然&#xff0c;我这个是在WSL 的linux上安装的&#xff0c;Windows一样的。 VSCode扩展商店网页链接&#xff1a;https://marketplace.visualstudio.com/vscode

时序预测 | Matlab实现SOM-BP自组织映射结合BP神经网络时间序列预测

时序预测 | Matlab实现SOM-BP自组织映射结合BP神经网络时间序列预测 目录 时序预测 | Matlab实现SOM-BP自组织映射结合BP神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现SOM-BP自组织映射结合BP神经网络时间序列预测&#xff08;完整源码…

LeetCode-994. 腐烂的橘子【广度优先搜索 数组 矩阵】

LeetCode-994. 腐烂的橘子【广度优先搜索 数组 矩阵】 题目描述&#xff1a;解题思路一&#xff1a;多源广度优先搜索&#xff08;队列实现&#xff09;解题思路二&#xff1a;哈希表实现&#xff0c;先找出所有腐烂和新鲜橘子的集合{}类似于set()。每剔除一次time1解题思路三&…

ChernoCPP 2

视频链接&#xff1a;【62】【Cherno C】【中字】C的线程_哔哩哔哩_bilibili 参考文章&#xff1a;TheChernoCppTutorial_the cherno-CSDN博客 Cherno的C教学视频笔记&#xff08;已完结&#xff09; - 知乎 (zhihu.com) C 的线程 #include<iostream> #include<th…

微信小程序怎么制作?制作一个微信小程序需要多少钱?

随着移动互联网的快速发展&#xff0c;微信小程序已成为连接用户与服务的重要桥梁。它以其便捷性和易用性&#xff0c;为各类企业和个人提供了一个全新的展示和交易平台。那么&#xff0c;如何制作一个微信小程序&#xff1f;又需要投入多少资金呢&#xff1f;本文将为您提供全…

H5面临的网络安全威胁和防范措施

H5&#xff0c;是基于HTML5技术的网页文件。HTML&#xff0c;全称Hyper Text Markup Language&#xff0c;即超文本标记语言&#xff0c;由Web的发明者Tim Berners-Lee与同事Daniel W. Connolly共同创立。作为SGML的一种应用&#xff0c;HTML编写的超文本文档能够独立于各种操作…

【性能测试】接口测试各知识第2篇:学习目标,1. 理解接口的概念【附代码文档】

接口测试完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;接口测试&#xff0c;学习目标学习目标,2. 接口测试课程大纲,3. 接口学完样品,4. 学完课程,学到什么,5. 参考:,1. 理解接口的概念。学习目标&#xff0c;RESTFUL1. 理解接口的概念,2.什么是接口测试…

文件夹0字节:原因、恢复与预防全攻略

在日常使用电脑或移动设备的过程中&#xff0c;我们经常会遇到一些数据问题&#xff0c;其中文件夹0字节的问题尤为常见且令人头疼。当原本存储着重要文件的文件夹突然变为0字节&#xff0c;我们往往感到束手无策。面对这种情况&#xff0c;我们不仅要了解问题的原因&#xff0…

【RealSense】Ubuntu20.04 安装 Intel® RealSense™ ROS 并使用 D435i 测试

【RealSense】Ubuntu20.04 安装 Intel RealSense™ ROS 并使用 D435i 测试 1 本机环境2 安装流程3 存在的 bug3.1 Resource not found: rgbd_launch 1 本机环境 Ubuntu20.04ROS Noetic 2 安装流程 参考文档: Link 安装 Intel RealSense™ SDK 2.0&#xff0c;参考上一篇文章:…

基于spring boot的漫画之家系统

基于spring boot的漫画之家系统设计与实现 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&…

ML.NET(二) 使用机器学习预测表情分析

这个例子使用模型进行表情分析&#xff1a; 准备数据&#xff1a; happy,sad 等&#xff1b; using Common; using ConsoleApp2; using Microsoft.ML; using Microsoft.ML.Data; using System.Diagnostics; using static Microsoft.ML.Transforms.ValueToKeyMappingEstimator;…