Redis和Mysql如何保证数据一致?面试可以这样说自己的看法

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 阿粉的小学弟最近开始了面试,毕竟也算是工作过一两年的人,现在面试也都开始造飞机了,小学弟开始在面试官面前疯狂造飞机了,也不知道这个飞机好不好用,而开始造飞机的这块内容,就是关于 Redis 的,而面试官问 Redis 的最多的问题,就是如何保证你的 Redis和 MySQL 数据的一致性?接下来我们分别分几种情况来考虑一下这个问题吧。

Redis 和 MySQL 搭配使用在什么地方?

缓存量大但又不常变化的数据

也就是说,当我们在使用 Redis 和 MySQL 的时候,搭配使用的地方就是,数据量比较大,但是这个数据不会经常的变换的位置,比如说,某些商品信息的评论数据,也就是让 Redis 充当 MySQL 的缓存服务器,而要实现的目标也是比较简单的,当客户要查询数据的时候,先访问我们的 Redis ,当 Redis 里面没有数据的时候,从 MySQL 中读取数据,并且存储到 Redis 中。

45.jpg

这个时候 Redis 和 MySQL 的交互就是两部分:

第一部分:同步MySQL数据到Redis

第二部分:同步Redis到MySql

这两部分的内容,实际上就是在一组业务操作中完成的,商品评论信息写入 Redis,如果没有,从 MySQL 中读取,然后写入 Redis。

而接下来的问题就比较严重了,Redis 和 MySQL 数据库数据如何保持一致性?

Redis 和 MySQL 数据库数据如何保持一致性?

为什么会存在这样的一个问题呢?阿粉用网上拿过来的图给大家分析一波。

46.jpg

首先,当我们请求发送到服务器的时候,这个时候,我们先去缓存里面拿我们需要的数据,如果没有的话,我们就去数据库加载数据,加载完成之后,然后再把数据写入到缓存里面。

接下来问题来了,如果你的读和写存在并发的时候,会出现什么样子的问题呢?这个时候,我们就比较尴尬了,压根就没办法保证读和写的顺序,这时候就出现了 Redis 和 MySQL 数据不一致的问题了。

我们准备多种不同的方案来进行不同的分析。

1.先更新数据库,再更新缓存

为什么不考虑这种使用方案呢?

假设我们现在有两个请求 一个是 A  一个是 B ,假设 A 这时候进行请求,A 先更新数据库,接着 B 请求来了, B 更新数据库,结果 B 请求快,B 直接先更新了缓存,这时候缓存更新的内容为 B 更新的,也就是 b ,然后 A 这时候更新完数据库之后,又要更新缓存,这时候 A 更新了缓存,结果最后,缓存里面保存的数据是 a 。

也就是这样的

A ---> 更新数据库 ----> 更新缓存为a 我更新数据库慢,我存了个a

B ---> 更新数据库 ----> 更新缓存为b 我更新数据库快,我存了个b

本来应该最后更新完成之后的缓存中应该是 b ,结果最后出现了 a ,如果出现这种问题的时候,领导来看的时候,通常挨整的还是程序员自己呀。

这时候,在缓存里面存在的就应该算是脏数据了,所以,这种方案不推荐。

47.jpg

  1. 先更新缓存,再更新数据库

同样的 A B 两个请求,比如说这时候,A请求要进行一个写的操作,而 B 请求要进行一个读取的操作,这时候,A 肯定要删除缓存,就这这个时候,B 来了,我要读取,结果,缓存里面数据不存在,就直接去读数据库,然后把数据库的内容写入到缓存里面了,而这个时候的数据是 A 还没有进行过修改的数据,也就是一个老数据,等读完了之后,A进行了修改,这时候,你的缓存和你数据库中的数据就会出现不一样的情况了。

因为写和读是并发的,没法保证顺序,就会出现缓存和数据库的数据不一致的问题,这种方案,同样不可行。

那么我们应该怎么样去保证 Redis 和 MySQL 数据一致性呢?

如何保证 Redis 和 MySQL 数据一致性。

这时候就会有两个在面试的时候,说分布式很容易给自己挖了个大坑的地方,那就是最终一致性和强一致性,而数据库和缓存双写,就必然会存在不一致的问题。

这个命题就会有很感人的地方,你要做出一个选择,如果你选择强一致性,那就不能放缓存,所以,我们也就是仅仅能够保证最终的一致性,而如果选择强一致性,那算了,你别用缓存了。

而且我们说的这个,只是说降低概率发生,而不能完全的避免,但是我们还是要说。

延时双删策略

在写库前后都进行 Redis 的删除操作,并且第二次删除通过延迟的方式进行

那么应该是什么样子的实现逻辑呢?

  • 第一步:先删除缓存
  • 第二步:再写入数据库
  • 第三步:休眠xxx毫秒(根据具体的业务时间来定)
  • 第四步:再次删除缓存。

中间的休眠时间,根据自己的业务时间来进行定夺,这个双删策略实际上就是为了解决你在读数据的时候,生成的过期的数据被第二次写的操作给删除掉。

总有面试官喜欢问为什么要双删,因为第一次删除的是还没更新前的数据,第二次删除则是因为读取的并发性导致的缓存重新写入数据出现的垃圾数据。

这时候总有杠精面试官会问:如果你们的删缓存失败了,怎么办?那不是还是会出现缓存和数据库不一致的情况么?

比如一个写数据请求,然后写入数据库了,删缓存失败了,这会就出现不一致的情况了。

这时候我们就需要一个中间件的无私配合了,那就是使用消息来进行重试机制。

步骤:

  1. 业务代码去更新数据库
  2. 数据库的操作进行记录日志。
  3. 订阅程序提取出所需要的数据以及key
  4. 获得该信息尝试删除缓存,发现删除失败的时候,发送消息到消息队列
  5. 继续重试删除缓存的操作,直到删除缓存成功。

其实这个方法和另外一个地方很像,分布式事务的处理方式,就是保证数据的最终一致性,而在分布式事务中,则称之为这种为最大努力通知。

而为什么说是很像,实际上最大努力通知采用的实际上也是 MQ ,但是采用的是 MQ 的 ack 确认机制来进行完成的。

那么最大努力通知又是什么样的流程呢?

  1. 业务方把通知发送给 MQ
  2. 接收通知方监听 MQ
  3. 接收通知方接收消息,业务处理完成回应ack
  4. 接收通知方若没有回应ack则MQ会重复通知,MQ 按照间隔时间从短到长的方式逐步拉大通知间隔,直到达到通知要求的时间上限,比如24小时之后不再进行通知。
  5. 接收通知方可通过消息校对接口来校对消息的一致性

而为什么叫最大努力通知呢,实际上也很容易理解,他并没有从本质上解决问题,只是把问题数目从100 变成了 10 ,毕竟有些内容第一次没处理,第二次就可能会被处理掉。也就是说降低了这种有问题情况的发生,毕竟保证的都是最终一致性。

你面试的时候知道怎么和面试官 Battle 了么?

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
10天前
|
关系型数据库 MySQL Linux
在Linux环境下备份Docker中的MySQL数据并传输到其他服务器以实现数据级别的容灾
以上就是在Linux环境下备份Docker中的MySQL数据并传输到其他服务器以实现数据级别的容灾的步骤。这个过程就像是一场接力赛,数据从MySQL数据库中接力棒一样传递到备份文件,再从备份文件传递到其他服务器,最后再传递回MySQL数据库。这样,即使在灾难发生时,我们也可以快速恢复数据,保证业务的正常运行。
82 28
|
1月前
|
存储 SQL 关系型数据库
【YashanDB知识库】MySQL迁移至崖山char类型数据自动补空格问题
**简介**:在MySQL迁移到崖山环境时,若字段类型为char(2),而应用存储的数据仅为'0'或'1',查询时崖山会自动补空格。原因是mysql的sql_mode可能启用了PAD_CHAR_TO_FULL_LENGTH模式,导致保留CHAR类型尾随空格。解决方法是与应用确认数据需求,可将崖山环境中的char类型改为varchar类型以规避补空格问题,适用于所有版本。
|
29天前
|
消息中间件 NoSQL 关系型数据库
去哪面试:1Wtps高并发,MySQL 热点行 问题, 怎么解决?
去哪面试:1Wtps高并发,MySQL 热点行 问题, 怎么解决?
去哪面试:1Wtps高并发,MySQL 热点行 问题, 怎么解决?
|
30天前
|
SQL 关系型数据库 MySQL
【YashanDB知识库】字符集latin1的MySQL中文数据如何迁移到YashanDB
本文探讨了在使用YMP 23.2.1.3迁移MySQL Server字符集为latin1的中文数据至YashanDB时出现乱码的问题。问题根源在于MySQL latin1字符集存放的是实际utf8编码的数据,而YMP尚未支持此类场景。文章提供了两种解决方法:一是通过DBeaver直接迁移表数据;二是将MySQL表数据转换为Insert语句后手动插入YashanDB。同时指出,这两种方法适合单张表迁移,多表迁移可能存在兼容性问题,建议对问题表单独处理。
【YashanDB知识库】字符集latin1的MySQL中文数据如何迁移到YashanDB
|
1月前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
1. 先更新Mysql,再更新Redis,如果更新Redis失败,可能仍然不⼀致 2. 先删除Redis缓存数据,再更新Mysql,再次查询的时候在将数据添加到缓存中 这种⽅案能解决1 ⽅案的问题,但是在⾼并发下性能较低,⽽且仍然会出现数据不⼀致的问题,⽐如线程1删除了 Redis缓存数据,正在更新Mysql,此时另外⼀个查询再查询,那么就会把Mysql中⽼数据⼜查到 Redis中 1. 使用MQ异步同步, 保证数据的最终一致性 我们项目中会根据业务情况 , 使用不同的方案来解决Redis和Mysql的一致性问题 : 1. 对于一些一致性要求不高的场景 , 不做处理例如 : 用户行为数据 ,
|
1月前
|
消息中间件 缓存 NoSQL
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
|
2月前
|
SQL 关系型数据库 MySQL
基于SQL Server / MySQL进行百万条数据过滤优化方案
对百万级别数据进行高效过滤查询,需要综合使用索引、查询优化、表分区、统计信息和视图等技术手段。通过合理的数据库设计和查询优化,可以显著提升查询性能,确保系统的高效稳定运行。
85 9
|
1月前
|
关系型数据库 MySQL Java
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
|
1月前
|
关系型数据库 MySQL 数据库连接
docker拉取MySQL后数据库连接失败解决方案
通过以上方法,可以解决Docker中拉取MySQL镜像后数据库连接失败的常见问题。关键步骤包括确保容器正确启动、配置正确的环境变量、合理设置网络和权限,以及检查主机防火墙设置等。通过逐步排查,可以快速定位并解决连接问题,确保MySQL服务的正常使用。
301 82
|
1天前
|
负载均衡 算法 关系型数据库
大数据新视界--大数据大厂之MySQL数据库课程设计:MySQL集群架构负载均衡故障排除与解决方案
本文深入探讨 MySQL 集群架构负载均衡的常见故障及排除方法。涵盖请求分配不均、节点无法响应、负载均衡器故障等现象,介绍多种负载均衡算法及故障排除步骤,包括检查负载均衡器状态、调整算法、诊断修复节点故障等。还阐述了预防措施与确保系统稳定性的方法,如定期监控维护、备份恢复策略、团队协作与知识管理等。为确保 MySQL 数据库系统高可用性提供全面指导。
下一篇
oss创建bucket