如何保证缓存和 MySQL 的双写一致 ?

1. 如何保证缓存和 MySQL 的双写一致 ?

什么叫做如何保证缓存和 MySQL 双写一致,这个问题就是指当应用程序执行写(增删改)操作时,如何保证 Redis 和 MySQL 的数据一致性。

当用户发送请求时,程序的执行流程如下:

要保证 Redis 和 MySQL 的数据一致性,从大的角度来说,无非就两种思路:

1.修改

  • 先修改数据库,再修改 Redis
  • 先修改 Redis,再修改数据库

2.删除

  • 先删除 Redis,再操作数据库
  • 先操作数据库,再删除 Redis

这四种方式在正常情况下,都可以保证 Redis 和 MySQL 的数据一致性,但是在异常情况下,就只有一种方式才能真正保证 Redis 和 MySQL 的双写一致。

当上述方式,每个方案都是执行了前半部分后,主机掉电了 >>

① 先修改数据库,再修改 Redis(掉电)

这种方式,Redis 中是旧数据,而 MySQL 中是新数据,当应用程序访问 Redis 时,发现有数据,直接就返回给用户了,显然这种方式是不合理的。

② 先修改 Redis,再修改数据库(掉电)

这种方式,Redis 中是新数据,而 MySQL 中是旧数据,当应用程序访问 Redis 时,发现有数据,直接就返回给用户了,此时 Redis 和数据库中的数据也不一致,下一次 Redis 还需要从数据库中同步数据的,显然这种方式也不合理。

③ 先删除 Redis,再操作数据库(掉电)

这种方式,不管主机有没有掉电,Redis 始终没数据,始终 都是要从数据库中同步数据的,所以这种方式 Redis 和 MySQL 的数据一定是一致的。

④ 先操作数据库,再删除 Redis(掉电)

这种方式也是行不通的,操作完数据库,主机掉电,此时 Redis 中还是有数据的,而且是旧数据,而 MySQL 中的数据已经更新了,导致双写不一致。

【并发场景下的问题】

虽然先删除 Redis,再操作数据库,这种方式看似解决了 Redis 和 MySQL 中的双写一致问题,但是它的前提是要在单线程的情况下。

在多线程的场景下,由于操作系统的随机调度,可能会出现以下情况:

  1. 线程 1 执行完删除 Redis,然后时间片用完了,
  2. 线程 2 执行查询操作,由于线程 1 把 Redis 删除了,所以线程 2 拿到了数据库的旧数据,然后时间片用完了,
  3. 线程 1 继续执行更新数据库,并把新数据缓存至 Redis,执行结束,
  4. 线程 2 苏醒,将刚刚查到的数据,缓存一份至 Redis.

此时 Redis 和数据库中的数据又变成不一致了,那该怎办 ?

【解决办法】延时双删

在线程 2 执行完之后后,再删除一次 Redis,以便下次查询还得走数据库,此时拿到的就是最新的数据了。(此时线程 1 的缓存 Redis 就可以不必执行了)

如果在面试中碰到这个问题,回到到这里其实已经差不多了,如果遇到了刁钻一点的面试官,那么我们以上看似美好的推理过程,其实还是存在问题的。

面试官问:延时双删是否彻底解决了 Redis 和 MySQL 双写一致的问题 ?

答案是不一定,它只是最大限度的解决双写一致性问题。因为延时,延长的时间是固定的,而操作系统的调度是随机的,极端情况下,还是可能会存在线程 1 第二次删除操作 处在线程 2 的将旧数据缓存至 Redis这个操作之前。(极端情况下,线程 2 是个饥饿线程)

那这个问题该怎么完美解决 ?

这个问题我也问过一些大佬,他们给出的结论是从理论上来说,目前没有更好的解决方案,但是前面也说了只有极端情况下,连延时双删都解决不了,因为它发生的概率也是比较小的,所以可以忽略不计了,并且使用延时双删几乎可以解决 99.99% 的双写一致问题了。

如果硬要追求完美主义,可以给它设置一个过期时间,等到键值过期了,自然会把数据库中新的数据给保存到 Redis 中;

另外,对于主机掉电,另一半操作没有执行的问题,可以通过加入消息队里欸来解决(保证业务的完整性),消费者再消费任务的时候,即使掉电,下一次还是会继续消费的。

相关推荐
AI-好学者1 分钟前
阶段一-图数据库基础与PropertyGraph模型
数据库·rag·knowledge graph·graphrag
其实防守也摸鱼1 小时前
运维--学习阶段问题解答(1)(自测)
linux·运维·服务器·数据库·学习·自动化·命令模式
懒鸟一枚2 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
龙仔7252 小时前
SQL Server 创建只读账号完整操作(分两种场景:SSMS图形界面 + T-SQL脚本)
数据库·sql·oracle
霁月的小屋2 小时前
生产环境中的事务实践——银行系统上线记(四)
数据库
Database_Cool_2 小时前
AI 应用数据底座首选:阿里云 PolarDB 为大模型 RAG 提供一体化支撑
数据库·阿里云
玖玥拾2 小时前
C# 语言进阶(十五)C# 游戏服务端 MySQL 数据库
服务器·开发语言·网络·数据库·mysql·c#
IvorySQL4 小时前
PG 日报|社区讨论重构 pg_hba 配置文件格式
数据库·人工智能·postgresql·重构·ivorysql
逝水无殇4 小时前
C# 文件的输入与输出详解
开发语言·数据库·后端·c#