双写一致性方案对比

双写一致性方案对比

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

方案:

先写 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,数据的一致性也可以达到秒级;
  • 纯粹的高并发场景,不建议用这种方案,比如抢购、秒杀等。
相关推荐
独行侠影a1 小时前
SpringBoot 分布式锁实战:Redisson 解决订单超卖并发问题
spring boot·分布式·后端
妙码生花1 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(五十八):后台系统配置管理实现
前端·后端·go
IT_陈寒2 小时前
Java并行流把我坑惨了:原来不是线程安全的!
前端·人工智能·后端
Lihua奏3 小时前
跨域:浏览器到底拦住了什么
后端
Lyra_Infra3 小时前
Docker OCI Runtime 启动失败问题排查与解决
后端·docker·架构
XuCoder3 小时前
Redis 哨兵模式:它到底是怎么保证高可用的
后端
敲个大西瓜4 小时前
Springboot核心面试题
java·spring boot·后端
运维行者_5 小时前
网络监控与ITSM集成:从告警到工单,实现运维自动化闭环
开发语言·网络·分布式·后端·架构·flask·php
子兮曰5 小时前
解剖 Claude Code:从入口架构逆向工程看 AI 编程工具的信任边界设计
前端·后端·claude