Redis双写一致性(数据库与redis数据一致性)

一 什么是双写一致性?

当修改了数据库(MySQL)中的数据,也要同时更新缓存(redis)中的数据,缓存中的数据要和数据库中的数据保持一致

双写一致性,根据业务对时间上的要求,可以分为三种情况:

1、延时双删:较为准时的一致性,Redis中的数据和MySQL较为准时的一致,不会超过很长的时间

2、redissson锁:保证强一致性;准时

3、异步写入redis:如果业务允许短暂时间内redis与MySQL数据库中数据的不一致,但是保持最终一致的情况;

二 延时双删

2.1 延时双删的背景

背景:当数据库中的数据出现了变化,我是应该先删除缓存中的数据,还是先修改数据库中的数据,再删除缓存中的数据呢?

其实不管是先删除redis中的数据,还是先update数据库中的数据,都会导致数据不一致的问题

第一种情况:先删除Redis缓存,再更新MySQL数据库

当线程1删除了缓存,尚未更新数据库时,线程2进来了,查询redis中,没有这条数据,未命中,那么线程2会去查询数据库,并将结果写入缓存中;这时候线程1才会更新数据库的数据;

如图中的redis缓存中,还是原来的数据10,数据库以及改成了20,且由于redis中有数据,所有后续的线程不会再去查询数据库更新数据,这就导致了脏数据的产生

第二种情况:先操作MySQL数据库,再更新Redis

如果线程1去查询redis缓存的时候,Redis中的该条数据以及过期了,然后去查询数据库,尚未写入缓存时,线程2更新了数据库,再删除缓存;删除了缓存之后,线程1此时再获得CPU资源,去Redis中写入数据(这时候线程1拿着的还是老数据),也会导致Redis中和MySQL中的数据不一致

虽然这两种情况很少出现,但是一旦出现,就有可能对业务造成重大损失,是不可容忍的!

2.2 什么叫延时双删

就是上述背景两个方式的集合,先删除Redis中的数据,在更新MySQL数据库中的数据,最后再次删除Redis中的数据;至于延时

为什么要延时呢?

现在大部分业务的数据库,都是主从集群的数据库;修改数据库之后,如果立马删除Redis中的数据,主库的数据尚未同步到从库,而后续有其他线程从从库中查询到尚未同步过来的数据写入redis,还是会导致脏数据的风险,所以要延时(可以用定时器,或延时队列等)再删除一次redis中的数据

注:由于你是无法绝对确认什么时候数据库进行主从同步的,所以哪怕你延时了,还是有可能在数据库同步之前删掉Redis,然后其他线程获取脏数据导致不一致的情况的!所以延时双删,无法保证强一致性

三 redisson锁

如果业务必须要求,保持Redis和MySQL数据库中的数据,实时的强一致性,那么我们可以使用分布式锁,和redisson提供的读写锁来保证数据的同步

3.1分布式锁(互斥锁)

如图所示,给资源加上一个互斥锁:当线程1要更新MySQL数据库和删除Redis中的数据前,加互斥锁,这样其他线程无法获取Redis中的数据,只能等线程1写入MySQL,并删除缓存完成释放锁后,才能读取数据;

但是很明显,这样的互斥锁虽然保证了强一致性,但是性能很低,充斥大量的获取锁和释放锁的额外开销

3.2 共享锁和排他锁

由于我们的现实情况中,对Redis中的数据,肯定是读多写少的;所以没必要使用互斥锁

这时我们可以使用redisson提供的共享锁和排他锁

当某一个线程要更新MySQL和删除Redis中的数据时,就必须先获得排他锁(其他线程无法读)这样删除完成后,其他线程才能获取共享锁以读取数据

代码实现参考如下:

使用共享锁的优缺点:

优点:强一致性

缺点:还是性能低,只比互斥锁强

四 异步写入redis

当业务不要求redis中的数据,立马从MySQL中同步出来时,我们就可以使用异步的方式来实现双写一致性了,这样既没有性能问题,也保证了双写一致性

4.1异步通知

当更新了MySQL中的数据,需要写入redis时,可以发送一个异步消息,放到MQ中,由专门的消费者去写入redis中

4.2 canal

canal是阿里巴巴出的一种中间件,基于MySQL的主从同步来实现的:

当有数据写入数据库,数据库进行主从同步时,会把所有ddl和dml的语句记录到一个binlog文件中;

而canal的作用就是伪装成一个MySQL的从节点,去监听这个binlog日志,把MySQL中我们监听的数据的变化,异步通知给缓存服务,进行写入redis中

canal的优点是:对业务代码几乎无侵入,前文中的方式多多少少对代码都有侵入,而且速度很快

写在后面:

其实,我们公司的真实方式,并不是写入MySQL后,删除redis的数据,再由下一个线程查询MySQL写入redis;

而是,直接写入MySQL后,再立马直接更新写入redis中,按我的理解,这样的方式很直接,很有效,既保证了时效性,也保证了强一致性,并没有什么缺点;

如果有大佬看到这篇文章,烦请可以给我解释一下,我们公司的这样操作的缺点是什么,感激不尽

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

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

相关文章

C32.【C++ Cont】静态实现双向链表及STL库的list

目录 1.知识回顾 2.静态实现演示图 3.静态实现代码 1.初始双向链表 2.头插 3.遍历链表 4.查找某个值 4.任意位置之后插入元素 5.任意位置之前插入元素 6.删除任意位置的元素 4.STL库的list 1.知识回顾 96.【C语言】数据结构之双向链表的初始化,尾插,打印和尾删 97.【C…

二级C语言题解:矩阵主、反对角线元素之和,二分法求方程根,处理字符串中 * 号

目录 一、程序填空📝 --- 矩阵主、反对角线元素之和 题目📃 分析🧐 二、程序修改🛠️ --- 二分法求方程根 题目📃 分析🧐 三、程序设计💻 --- 处理字符串中 * 号 题目&#x1f…

采用idea中的HTTP Client插件测试

1.安装插件 采用idea中的HTTP Client插件进行接口测试,好处是不用打开post/swagger等多个软件,并且可以保存测试时的参数,方便后续继续使用. 高版本(2020版本以上)的idea一般都自带这个插件,如果没有也可以单独安装. 2.使用 插件安装完成(或者如果idea自带插件),会在每个Con…

探讨如何在AS上构建webrtc(2)从sdk/android/Build.gn开始

全文七千多字,示例代码居多别担心,没有废话,不建议跳读。 零、梦开始的地方 要发美梦得先入睡,要入睡得找能躺平的地方。那么能躺平编译webrtc-android的地方在哪?在./src/sdk/android/Build.gn。Build.gn是Build.nin…

Linux firewalld开启日志审计功能(2)

在Firewalld防火墙中启用和配置logdenied选项,记录被拒绝的数据包(等同于开启日志功能) 效果展示: 1.开启日志记录功能 firewall-cmd --set-log-deniedunicast #重新加载生效配置 firewall-cmd --reload 2.配置rsyslog捕获日志…

Spring Web MVC项目的创建及使用

一、什么是Spring Web MVC? Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中,通常被称为Spring MVC。 1.1 MVC的定义 MVC 是 Model View Controller 的缩写,它是软件工程中的一种软件架构…

oracle:索引(B树索引,位图索引,分区索引,主键索引,唯一索引,联合索引/组合索引,函数索引)

索引通过存储列的排序值来加快对表中数据的访问速度,帮助数据库系统快速定位到所需数据,避免全表扫描 B树索引(B-Tree Index) B树索引是一种平衡树结构,适合处理范围查询和精确查找。它的设计目标是保持数据有序,并支持高效的插入…

android 适配 api 35(android 15) 遇到的问题

首先升级 targetSdkVersion 和 compileSdkVersion 到 35,升级后发生的报错 一、 解决方案: 升级 gradle 和 gradle 插件版本 com.android.tools.build:gradle -> 8.3.0-alpha02 gradle-wrapper.properties : distributionUrl -> gradle-8.6-bin.zip htt…

@Value属性读取系统变量错误

Value属性读取配置属性错误 场景 在测试Value读取yml配置文件属性时,发现系统配置属性优先级高于配置文件,导致注入异常值: 配置文件: user:name: yanxin测试类: RestController RequestMapping("/books") public class BookC…

BFS算法——广度优先搜索,探索未知的旅程(下)

文章目录 前言一. N叉树的层序遍历1.1 题目链接:https://leetcode.cn/problems/n-ary-tree-level-order-traversal/description/1.2 题目分析:1.3 思路讲解:1.4 代码实现: 二. 二叉树的锯齿形层序遍历2.1 题目链接:htt…

【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题

【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题 零、起因 最近在使用Ubuntu虚拟机编译ARM程序,解压ARM的GCC后想要启动,报“没有那个文件或目录”,但是文件确实存在,环境配置也检查过了没问题,本文记…

清理服务器/docker容器

清理服务器 服务器或docker容器清理空间。 清理conda环境 删除不用的conda虚拟环境: conda env remove --name python38 conda env remove --name python310清理临时目录:/tmp du -sh /tmp # 查看/tmp目录的大小/tmp 目录下的文件通常是可以直接删除…

康谋方案 | BEV感知技术:多相机数据采集与高精度时间同步方案

随着自动驾驶技术的快速发展,车辆准确感知周围环境的能力变得至关重要。BEV(Birds-Eye-View,鸟瞰图)感知技术,以其独特的视角和强大的数据处理能力,正成为自动驾驶领域的一大研究热点。 一、BEV感知技术概…

HarmonyOS 5.0应用开发——ContentSlot的使用

【高心星出品】 文章目录 ContentSlot的使用使用方法案例运行结果 完整代码 ContentSlot的使用 用于渲染并管理Native层使用C-API创建的组件同时也支持ArkTS创建的NodeContent对象。 支持混合模式开发,当容器是ArkTS组件,子组件在Native侧创建时&#…

脚本一键生成管理下游k8s集群的kubeconfig

一、场景 1.1 需要管理下游k8s集群的场景。 1.2 不希望使用默认的cluster-admin权限的config. 二、脚本 **重点参数: 2.1 配置变量。 1、有单独namespace的权限和集群只读权限。 2、自签名的CA证书位置要正确。 2.2 如果配置错误,需要重新…

windows安装linux子系统【ubuntu】操作步骤

1.在windows系统中开启【适用于Linux的Windows子系统】 控制面板—程序—程序和功能—启用或关闭Windows功能—勾选适用于Linux的Windows子系统–确定 2.下载安装Linux Ubuntu 22.04.5 LTS系统 Ununtu下载链接 3.安装完Ununtu系统后更新系统 sudo apt update4.进入/usr/l…

LabVIEW自定义测量参数怎么设置?

以下通过一个温度采集案例,说明在 LabVIEW 中设置自定义测量参数的具体方法: 案例背景 ​ 假设使用 NI USB-6009 数据采集卡 和 热电偶传感器 监测温度,需自定义以下参数: 采样率:1 kHz 输入量程:0~10 V&a…

老游戏回顾:G2

一个老的RPG游戏。 剧情有独到之处。 ------- 遥远的过去,古拉纳斯将希望之光给予人们,人类令希望之光不断扩大,将繁荣握在手中。 但是,暗之恶魔巴鲁玛将光从人类身上夺走。古拉纳斯为了守护人类与其展开了一场激战&#xff0c…

DeepSeek R1 Distill Llama 70B(免费版)API使用详解

DeepSeek R1 Distill Llama 70B(免费版)API使用详解 在人工智能领域,随着技术的不断进步,各种新的模型和应用如雨后春笋般涌现。今天,我们要为大家介绍的是OpenRouter平台上提供的DeepSeek R1 Distill Llama 70B&…

【LeetCode: 887. 鸡蛋掉落 + 递归 + 二分 + dp】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…