Mysql 、Redis 数据双写一致性 更新策略与应用

零、important point

1. 缓存双写一致性问题

2. java实现逻辑(对于  QPS <= 1000  可以使用)

public class UserService {public static final String CACHE_KEY_USER = "user:";@Resourceprivate UserMapper userMapper;@Resourceprivate RedisTemplate redisTemplate;/*** 业务逻辑没有写错,对于小厂中厂(QPS《=1000)可以使用,但是大厂不行* @param id* @return*/public User findUserById(Integer id){User user = null;String key = CACHE_KEY_USER+id;//1 先从redis里面查询,如果有直接返回结果,如果没有再去查询mysqluser = (User) redisTemplate.opsForValue().get(key);if(user == null){//2 redis里面无,继续查询mysqluser = userMapper.selectByPrimaryKey(id);if(user == null){//3.1 redis+mysql 都无数据//你具体细化,防止多次穿透,我们业务规定,记录下导致穿透的这个key回写redisreturn user;}else{//3.2 mysql有,需要将数据写回redis,保证下一次的缓存命中率redisTemplate.opsForValue().set(key,user);}}return user;}

其中存在的问题是:在高并发的场景下,(加入redis中没有)会有大量请求打在mysql上。

解决策略:

        (多个线程同时查询数据库某条数据时)

===》在第一个数据的请求上(加上一个互斥锁)

===》等待第一个线程查询到了数据 , 并做了缓存

===》后面的线程进来发现已经有缓存了 

===》直接走缓存

/*** 加强补充,避免突然key失效了,打爆mysql,做一下预防,尽量不出现击穿的情况。* @param id* @return*/public User findUserById2(Integer id){User user = null;String key = CACHE_KEY_USER+id;//1 先从redis里面查询,如果有直接返回结果,如果没有再去查询mysql,// 第1次查询redis,加锁前user = (User) redisTemplate.opsForValue().get(key);if(user == null) {//2 大厂用,对于高QPS的优化,进来就先加锁,保证一个请求操作,让外面的redis等待一下,避免击穿mysqlsynchronized (UserService.class){//第2次查询redis,加锁后user = (User) redisTemplate.opsForValue().get(key);//3 二次查redis还是null,可以去查mysql了(mysql默认有数据)if (user == null) {//4 查询mysql拿数据(mysql默认有数据)user = userMapper.selectByPrimaryKey(id);if (user == null) {return null;}else{//5 mysql里面有数据的,需要回写redis,完成数据一致性的同步工作redisTemplate.opsForValue().setIfAbsent(key,user,7L,TimeUnit.DAYS);}}}}return user;}

3. 数据一致性的理解

(1)如果 redis 中有数据   ===》  需要和  数据库中的值相同

(2)如果 redis 中没有数据  ===》  数据库中的值的是最新值,  回写到redis中

(3)缓存按照操作来分

        1.只读缓存(没有回写操作,少数情况下)

        2.读写缓存

                2.1 同步直写策略

                写数据库后也同步写redis缓存(热点数据、VIP重要数据 ==》这一秒填写、下一秒更新)

                2.2 异步缓写策略

                mysql数据变动了,可以允许业务上一定时间后作用于redis(仓库、物流系统、积分变更等 ==》 允许一定时延后缓存更新)

                可能会出现异常,借助kafka 或者 RabbitMQ 等消息中间件 ,实现重试重写

4. 数据库和缓存一致性的  几种策略

目的 :  达到最终的一致性

做法 :  给缓存设置过期时间   定期清理缓存并回写    ==》 保证最终一致性

1.停机

        (eg)凌晨升级  先往mysql灌入10000条数据, 在解决与mysql同步问题

2. 4种 更新策略

        (1)先更新数据库,在更新缓存

        (2)先更新缓存,在更新数据库

        (3)先删除缓存,在更新数据库

        (4)先更新数据库,在删除缓存

一、4种 更新策略

(1)先更新数据库,在更新缓存

Q1:redis回写失败,读到的是redis的脏数据

        1.先更新mysql的某商品的库存,当前商品的库存是100,更新为99个。
        2.先更新mysql修改为99成功,然后更新redis。
        3.此时假设异常出现,更新redis失败了,这导致mysql里面的库存是99而redis里面的还是100
        4.上述发生,会让数据库里面和缓存redis里面数据不一致,读到redis脏数据

Q2: 多线程对于同一份数据update, 回写redis出岔子,数据的写入覆盖

最终导致 mysql 80 , redis 100

(2)先更新缓存,在更新数据库(不太推荐)

Q1: 不太推荐 ==》 业务上一般把 mysql 作为底单数据库,保证最后的解释

Q2:多线程对于同一份数据update, 写入mysql出岔子,数据的写入覆盖

(3)先删除缓存,在更新数据库

Q1: 会出现延时

Q2: 此时redis里面的数据是空的,B线程来读取,先去读redis里数据(已经被A线程delete掉了),此处出来2个问题:

  2.1     B从mysql获得了旧值

       B线程发现redis里没有(缓存缺失)马上去mysql里面读取,从数据库里面读取来的是旧值

  2.2     B会把获得的旧值写回redis 

     获得旧值数据后返回前台并回写进redis(刚被A线程删除的旧数据有极大可能又被写回了)。

Q3:A线程更新完mysql,发现redis里面的缓存是脏数据,A线程直接懵逼了,o(╥﹏╥)o

        两个并发操作,一个是更新操作,另一个是查询操作,

        A删除缓存后,B查询操作没有命中缓存,B先把老数据读出来后放到缓存中,然后A更新操作更新了数据库。

        于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的,而且还一直这样脏下去了。

解决策略

1. 采用延时双删策略

(4)先更新数据库,在删除缓存

1.异常问题

 2.业务指导思想

2.1 微软云

2.2 阿里巴巴cache

 3.解决方案

1 可以把要删除的缓存值或者是要更新的数据库值暂存到消息队列中(例如使用Kafka/RabbitMQ等)。

2 当程序没有能够成功地删除缓存值或者是更新数据库值时,可以从消息队列中重新读取这些值,然后再次进行删除或更新。
3 如果能够成功地删除或更新,我们就要把这些值从消息队列中去除,以免重复操作,此时,我们也可以保证数据库和缓存的数据一致了,否则还需要再次进行重试
4 如果重试超过的一定次数后还是没有成功,我们就需要向业务层发送报错信息了,通知运维人员。

 4.经典分布式事务问题

最终一致性体现案例:

1.流量充值,先下发短信,实际充值滞后5min

2.电商下单,先下发短信,具体物流明天见

 (0)如何选择方案

大多数业务场景:

        优先使用先更新数库,在删除缓存的方案


四、面试题

1.使用缓存  会涉及到  redis缓存与数据库  双存储双写

双写  ==》 数据库一致性问题  ==》 如何解决呢?

2. 双写一致性, 先去操作 redis or mysql,   why?  

3.  延时双删  怎么说?

        应用在需要更新数据时,先删除缓存再更新mysql数据库的策略下,所发生A线程需要更新数据,第一次删除缓存,更新完数据后,再次删除缓存,再将更新后的数据写入缓存。

延时双删会遇到一些问题:

Q1:这个删除需要睡眠多久呢?

         一般来说,线程Asleep的时间,就需要大于线程B读取数据再写入缓存的时间。
        第一种方法:
        在业务程序运行的时候,统计下线程读数据和写缓存的操作时间自行评估自己的项目的读数据业务逻辑的耗时,以此为基础来进行估算。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上加百毫秒即可。
        这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。
        第二种方法:
        新启动一个后台监控程序,比如后面讲解的WatchDog监控程序,去加时

Q2:这种同步策略,吞吐量降低如何解决?

        启动一个线程来监听mysql是否更新完毕

4. 微服务查询  redis无  mysql有, 为保证数据 双写一致性 回写redis  需要注意什么?

==》 双检 加锁 策略

==》 避免 缓存击穿

5. redis 和 mysql 双写100%   会出纰漏,  做不到强一致性,  如何保证 最终一致性?

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

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

相关文章

如何申请免费SSL证书,把网站升级成HTTPS

HTTPS&#xff08;Hyper Text Transfer Protocol Secure&#xff09;是一种用于安全数据传输的网络协议&#xff0c;它可以有效地保护网站和用户之间的通信安全。然而&#xff0c;要使一个网站从HTTP升级到HTTPS&#xff0c;就需要一个SSL证书。那么&#xff0c;如何申请免费的…

Transformer模型详解01-Word Embedding

文章目录 前言Transformer 整体结构Transformer 的输入单词 Embedding原理CBOW 模型one-hot构建 CBOW 训练数据集构建 CBOW 神经网络训练 CBOW 神经网络 Skip-gram 模型one-hot构建 Skip-gram训练数据集训练 Skip-gram神经网络 Word2Vec实例数据训练保存和加载 前言 Transform…

STM32使用PWM控制舵机

STM32使用PWM控制舵机 1、舵机的控制原理 舵机是一种位置伺服驱动器&#xff0c;是一种带有输出轴的小装置。当我们向伺服器发送一个控制信号时&#xff0c;输出轴就可以转到特定的位置。只要控制信号持续不变&#xff0c;伺服机构就会保持相对的角度位置不变。如果控制信号发…

虹科Pico汽车示波器 | 免拆诊断案例 | 2006 款林肯领航员车发动机怠速抖动

故障现象 一辆2006款林肯领航员车&#xff0c;搭载5.4 L发动机&#xff0c;累计行驶里程约为26万km。该车因发动机怠速抖动故障进厂维修&#xff0c;维修人员更换了火花塞、点火线圈及凸轮轴位置传感器&#xff0c;清洗了积炭和喷油器&#xff0c;故障依旧&#xff0c;于是向笔…

02_c/c++开源库ZeroMQ

1.安装 C库 libzmq sudo apt install libzmq3-dev 实例: https://zeromq.org/get-started/?languagec&librarylibzmq# 编译依赖: pkg-config --cflags --libs libzmq or cat /usr/lib/x86_64-linux-gnu/pkgconfig/libzmq.pc -isystem /usr/include/mit-krb5 -I/usr/in…

Mybatis-Plus学习:快速入门、核心功能、扩展功能、插件功能

文章目录 MybatisPlus快速入门快速开始常见注解常见配置 核心功能条件构造器&#xff08;Wrapper&#xff09;自定义SQLService接口基本用法基础业务接口复杂业务接口Lamda查询Lamda更新批量新增 扩展功能代码生成代码生成器快速开发插件 静态工具逻辑删除枚举处理器JSON处理器…

一例MFC文件夹病毒的分析

概述 这是一个MFC写的文件夹病毒&#xff0c;通过感染USB设备传播&#xff0c;感染后&#xff0c;会向c2(fecure.info:443)请求指令来执行。 样本的基本信息 Verified: Unsigned Link date: 19:52 2007/7/5 MachineType: 32-bit MD5: 4B463901E5858ADA9FED28FC5…

在idea中连接mysql

IDE&#xff08;集成开发环境&#xff09;是一种软件应用程序&#xff0c;它为开发者提供编程语言的开发环境&#xff0c;通常集成了编码、编译、调试和运行程序的多种功能。一个好的IDE可以大幅提高开发效率&#xff0c;尤其是在进行大型项目开发时。IDE通常包括以下几个核心组…

AI系列:大语言模型的RAG(检索增强生成)技术(上)

前言 大型语言模型&#xff08;LLM&#xff09;虽然在生成文本方面表现出色&#xff0c;但仍然存在一些局限性&#xff1a;数据是静态的&#xff0c;而且缺乏垂直细分领域的知识。为了克服这些限制&#xff0c;有时候会进行进一步的模型训练和微调。在实际应用中&#xff0c;我…

leetcode 221 最大正方形面积

示例 3&#xff1a; 输入&#xff1a;matrix [["0"]] 输出&#xff1a;0 # 最大正方形面积 def max_square(matrix):m len(matrix)n len(matrix[0])if m 0 or n 0::return Nonemax_side 1dp [[0] * (n 1) for _ in range(m 1)]for i in range(1, m 1):fo…

Linux进程——进程的概念(PCB的理解)

前言&#xff1a;在了解完冯诺依曼体系结构和操作系统之后&#xff0c;我们进入了Linux的下一篇章Linux进程&#xff0c;但在学习Linux进程之前&#xff0c;一定要阅读理解上一篇内容&#xff0c;理解“先描述&#xff0c;再组织”才能更好的理解进程的含义。 Linux进程学习基…

Unity 数字字符串逗号千分位

使用InputField时处理输入的数字型字符串千分位自动添加逗号&#xff0c;且自动保留两位有效数字 输入&#xff1a;123 输出&#xff1a;123.00 输入&#xff1a;12345 输出&#xff1a;12,345.00 代码非常简单 using UnityEngine; using TMPro;public class …

Elcomsoft iOS Forensics Toolkit: iPhone/iPad/iPod 设备取证工具包

天津鸿萌科贸发展有限公司是 ElcomSoft 系列取证软件的授权代理商。 Elcomsoft iOS Forensics Toolkit 软件工具包适用于取证工作&#xff0c;对 iPhone、iPad 和 iPod Touch 设备执行完整文件系统和逻辑数据采集。对设备文件系统制作镜像&#xff0c;提取设备机密&#xff08…

Linux网络-文件传输协议之FTP服务(附带命令及截图)

目录 一.FTP简介 二.FTP的数据模式 1.主动模式 2.被动模式 3.两种模式比较 三.安装配置vsftpd 1.安装vsftpd 1.1.安装前关闭防火墙 1.2.安装vsftpd 1.3.查看 1.4.备份 2.配置 3.重启后生效 四.相关实验 1.以win为例 1.1.设置并测试测试连通性 1.2.在终端里创建…

(mac)Prometheus监控之Node_exporter(CPU、内存、磁盘、网络等)

完整步骤 1.启动 Prometheus 普罗米修斯 prometheus --config.file/usr/local/etc/prometheus.yml 浏览器访问 http://localhost:9090/targets 2.启动Node_exporter node_exporter 访问&#xff1a;http://localhost:9100 3.启动grafana brew services start grafana 访问…

Pulsar【部署 02】Pulsar可视化工具Manager安装使用

Pulsar Manager 是一个基于 web 的 GUI 管理和监视工具&#xff0c;可帮助管理员和用户管理和监视租户、命名空间、主题、订阅、代理、集群等&#xff0c;并支持对多个环境进行动态配置。 可视化工具Manager安装使用 1.Docker1.1 拉取镜像并启动1.2 设置用户名密码1.3 登录并添…

基于SpringBoot+Vue高校实习管理系统的设计与实现

项目介绍&#xff1a; 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统高校实习管理系统信息管理难度大&#xf…

阿里开源黑白图片上色算法DDColor的部署与测试并将模型转onnx后用c++推理

阿里开源黑白图片上色算法DDColor的部署与测试并将模型转onnx后用c推理 文章目录 阿里开源黑白图片上色算法DDColor的部署与测试并将模型转onnx后用c推理简介环境部署下载源码安装环境下载模型 测试一下看看效果模型转onnx测试一下生成的onnx模型看看效果C 推理 简介 DDColor是…

Java集合框架-Collection-List-vector(遗留类)

目录 一、vector层次结构图二、概述三、底层数据结构四、常用方法五、和ArrayList的对比 一、vector层次结构图 二、概述 Vector类是单列集合List接口的一个实现类。与ArrayList类似&#xff0c;Vector也实现了一个可以动态修改的数组&#xff0c;两者最本质的区别在于——Vec…

Swish和H-Swish激活函数:提升模型训练效率

文章目录 Swish激活函数H-Swish激活函数实现总结参考 在深度学习领域&#xff0c;激活函数是神经网络中的关键组成部分&#xff0c;它决定了网络的输出和性能。近年来&#xff0c;研究人员提出了许多新的激活函数&#xff0c;其中Swish激活函数因其独特的性能优势而备受关注。这…