双写一致性方案对比

双写一致性方案对比

结论:先写数据库,再删缓存(一致性最优解决方案)

方案:

先写 Redis,再更新 MySQL

如果mysql写入失败了怎么办?

先写 MySQL,再更新Redis

问题很明显,并发请求下,A请求(写请求)先到达Mysql,但卡了一会儿,B请求(写请求)后到达,但是处理比A快,此时最新的数据应该是B,但是由于更新redis的操作A比B晚一点儿,导致redis数据为A的数据。

先删除 Redis,再写MySQL

redis 删除后,mysql写数据库的时间内,所有的读请求都打到mysql上了

A请求(写)删除缓存后,更新mysql数据,此时B请求(读)也进入了Mysql,B先完成查询操作,回写redis,A请求完成更新,此时正常的数据应该为A数据,但redis中写的B数据。 (主要是因为,写请求比较耗时,查询请求耗时较短,出现上述问题的可能性较大)

先删除 Redis,再写MySQL,再删除 Redis

经典的缓存双删问题,在上一个方案上有一些优化,让请求A等待一段时间,再删除缓存,保证蓝色的删除缓存在回写之后

  • "缓存双删"不要用无脑的 sleep 500 ms;
  • 通过消息队列的异步&串行,实现最后一次缓存删除;
  • 缓存删除失败,增加重试机制。

先写 MySQL,再删除 Redis

可能存在的问题:当请求A更新Mysql为11后 ,回写redis之前,请求B读取到了缓存中的数据,出现不一致

也就是在A请求更新Mysql后且删除redis之前的读取请求会有不一致问题(发生概率低)

另外考虑缓存刚好失效的情况

请求A 查询缓存,缓存失效,直接查询mysql,并回写缓存,在回写缓存前,请求B更新了mysql数据,删除缓存(此时没有缓存),然后A再回写缓存。 此时数据不一致,可能持续较久。

上述需要满足两个条件 缓存刚好过期、B请求更新mysql的时间,比A请求读取mysql+回写缓存 时间还长。(条件很难达到)

总结:读写并发,缓存不失效的情况下,会出现A(写请求)删除缓存之前 读取到的数据不对,持续时间短

读写并发,缓存恰好失效,会出现B(读请求)查询mysql - [A(写请求)更新了mysql,删除过期缓存] 回写redis之间

先写 MySQL,通过 Binlog,异步更新 Redis

主要是监听 MySQL 的 Binlog,然后通过异步的方式,将数据更新到 Redis,这种方案有个前提,查询的请求,不会回写 Redis

1、先写 MySQL,再删除 Redis

  • 比较推荐这种方式,删除 Redis 如果失败,可以再多重试几次,否则报警出来;
  • 这个方案,是实时性中最好的方案,在一些高并发场景中,推荐这种。

2、先写 MySQL,通过 Binlog,异步更新 Redis

  • 对于异地容灾、数据汇总等,建议会用这种方式,比如 binlog + kafka,数据的一致性也可以达到秒级;
  • 纯粹的高并发场景,不建议用这种方案,比如抢购、秒杀等。
相关推荐
井云AI1 小时前
井云智能体封装小程序:独立部署多开版 | 自定义LOGO/域名,打造专属AI智能体平台
人工智能·后端·小程序·前端框架·coze智能体·智能体网站·智能体小程序
Warren981 小时前
Spring Boot 拦截器返回中文乱码的解决方案(附全局优化思路)
java·网络·spring boot·redis·后端·junit·lua
练习时长一年2 小时前
SpringMVC相关自动配置
java·spring boot·后端
Victor3562 小时前
Redis(21)Redis的发布/订阅(Pub/Sub)机制是如何实现的?
后端
Victor3562 小时前
Redis(20) Redis的管道(Pipeline)是如何工作的?
后端
一枚小小程序员哈5 小时前
基于asp.net 的在线餐饮订餐系统的设计与实现/基于c#的网上订餐系统/餐厅管理系统
后端·c#·asp.net
你的人类朋友10 小时前
【Node&Vue】什么是ECMAScript?
前端·javascript·后端
你的人类朋友11 小时前
说说你对go的认识
后端·云原生·go
我崽不熬夜11 小时前
Java中基本的输入输出(I/O)操作:你知道如何处理文件吗?
java·后端·java ee
我崽不熬夜11 小时前
Java的异常处理机制:如何优雅地捕获和抛出异常?
java·后端·java ee