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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 阿粉的小学弟最近开始了面试,毕竟也算是工作过一两年的人,现在面试也都开始造飞机了,小学弟开始在面试官面前疯狂造飞机了,也不知道这个飞机好不好用,而开始造飞机的这块内容,就是关于 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
相关文章
|
23天前
|
SQL 关系型数据库 MySQL
大厂面试官:聊下 MySQL 慢查询优化、索引优化?
MySQL慢查询优化、索引优化,是必知必备,大厂面试高频,本文深入详解,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验分享。
大厂面试官:聊下 MySQL 慢查询优化、索引优化?
|
26天前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
27天前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
在项目中,为了解决Redis与Mysql的数据一致性问题,我们采用了多种策略:对于低一致性要求的数据,不做特别处理;时效性数据通过设置缓存过期时间来减少不一致风险;高一致性但时效性要求不高的数据,利用MQ异步同步确保最终一致性;而对一致性和时效性都有高要求的数据,则采用分布式事务(如Seata TCC模式)来保障。
58 14
|
1月前
|
SQL 算法 关系型数据库
面试:什么是死锁,如何避免或解决死锁;MySQL中的死锁现象,MySQL死锁如何解决
面试:什么是死锁,死锁产生的四个必要条件,如何避免或解决死锁;数据库锁,锁分类,控制事务;MySQL中的死锁现象,MySQL死锁如何解决
|
1月前
|
SQL NoSQL 关系型数据库
2024Mysql And Redis基础与进阶操作系列(13)作者——LJS[你个小黑子这都还学不会嘛?你是真爱粉嘛?真是的 ~;以后请别侮辱我家鸽鸽]
MYSQL日志之详解如何配置查看二进制、查询及慢查询日志;备份与恢复等具体详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
2024Mysql And Redis基础与进阶操作系列(13)作者——LJS[你个小黑子这都还学不会嘛?你是真爱粉嘛?真是的 ~;以后请别侮辱我家鸽鸽]
|
1月前
|
存储 SQL NoSQL
2024Mysql And Redis基础与进阶操作系列(10)作者——LJS[你个IKUN还学不会嘛?你是真爱粉嘛?真是的 ~;以后别侮辱我家鸽鸽]
Mysql And Redis基础与进阶操作系列之存储函数和MySQL 触发器等具体举例以及详解步骤;注意点及常见报错问题所对应的解决方法]
|
NoSQL 关系型数据库 PHP
|
2月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
78 6
|
28天前
|
存储 缓存 NoSQL
【赵渝强老师】基于Redis的旁路缓存架构
本文介绍了引入缓存后的系统架构,通过缓存可以提升访问性能、降低网络拥堵、减轻服务负载和增强可扩展性。文中提供了相关图片和视频讲解,并讨论了数据库读写分离、分库分表等方法来减轻数据库压力。同时,文章也指出了缓存可能带来的复杂度增加、成本提高和数据一致性问题。
【赵渝强老师】基于Redis的旁路缓存架构
|
1月前
|
缓存 NoSQL Redis
Redis 缓存使用的实践
《Redis缓存最佳实践指南》涵盖缓存更新策略、缓存击穿防护、大key处理和性能优化。包括Cache Aside Pattern、Write Through、分布式锁、大key拆分和批量操作等技术,帮助你在项目中高效使用Redis缓存。
193 22