双写一致性方案对比

双写一致性方案对比

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

方案:

先写 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,数据的一致性也可以达到秒级;
  • 纯粹的高并发场景,不建议用这种方案,比如抢购、秒杀等。
相关推荐
日月星辰Ace27 分钟前
jwk-set-uri
java·后端
用户1083863868034 分钟前
95%开发者不知道的调试黑科技:Apipost让WebSocket开发效率翻倍的秘密
前端·后端
疏狂难除1 小时前
基于Rye的Django项目通过Pyinstaller用Github工作流简单打包
后端·python·django
钢板兽1 小时前
Java后端高频面经——JVM、Linux、Git、Docker
java·linux·jvm·git·后端·docker·面试
未完结小说1 小时前
声明式远程调用:OpenFeign 基础教程
后端
MickeyCV2 小时前
《苍穹外卖》SpringBoot后端开发项目重点知识整理(DAY1 to DAY3)
java·spring boot·后端·苍穹外卖
uhakadotcom2 小时前
ClickHouse入门:快速掌握高性能数据分析
后端·面试·github
雷渊2 小时前
深入分析mysql中的binlog和redo log
java·后端·面试
uhakadotcom2 小时前
Pydantic Extra Types:扩展数据类型的强大工具
后端·面试·github
uhakadotcom2 小时前
Spring Fu:让Spring Boot启动提速40%的黑科技
后端·面试·github