双写一致性方案对比

双写一致性方案对比

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

方案:

先写 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,数据的一致性也可以达到秒级;
  • 纯粹的高并发场景,不建议用这种方案,比如抢购、秒杀等。
相关推荐
逍遥德5 分钟前
SpringBoot自带TaskScheduler 接口实现定时任务的动态增、删、启、停。
java·spring boot·后端·中间件
jieyucx1 小时前
Go 语言核心关键字:defer 深度解析与实战避坑
开发语言·后端·golang·defer
南囝coding2 小时前
Anthropic 内部数百个 Claude Code Skills,他们总结的这套方法值得看
前端·后端
Rust研习社2 小时前
Ubuntu 全面拥抱 Rust 后,我意识到 Rust 社区要变了
linux·服务器·开发语言·后端·ubuntu·rust
小江的记录本3 小时前
【AI大模型选型指南】《2026年5月(最新版)国内外主流AI大模型选型指南》(个人版)
前端·人工智能·后端·ai·aigc·ai编程·ai写作
我叫黑大帅3 小时前
基于 Docker + Watchtower 自动化部署后端服务
后端·docker·面试
fox_lht3 小时前
12.3.使用生命周期使引用一直有用
开发语言·后端·rust
fengxin_rou4 小时前
用户模块架构实战:DTO 与 Domain 分层、Optional 空值处理、事务只读优化详解
java·后端·架构·用户实战
程序员cxuan4 小时前
看了一下姚顺宇的访谈,确实太顶了。
人工智能·后端·程序员
Wy_编程4 小时前
Go语言中的指针
开发语言·后端·golang