缓存与 mysql 数据一致性问题把我搞疯了

2016-03-22 14:55:08 +08:00
 eightqueen

场景是这样的: 一主二从,用户更改数据,先淘汰缓存,再往主库写数据(缓存的数据需要经过业务计算,所以不能直接更新缓存),此时用户读数据,这个读操作也许发生在写数据成功之前,也许发生在主从同步成功之前,总之读了脏数据写到缓存里,怎么办?

2801 次点击
所在节点    问与答
12 条回复
xing393939
2016-03-22 14:58:06 +08:00
“缓存的数据需要经过业务计算,所以不能直接更新缓存”
认为应该直接更新缓存,计算就计算呗
jasontse
2016-03-22 15:00:50 +08:00
先写数据后淘汰缓存?
UnisandK
2016-03-22 15:01:22 +08:00
锁表?
stackboom
2016-03-22 15:08:36 +08:00
淘汰缓存-》写数据-》更新缓存。 58 沈剑 写过缓存与数据库数据一致性的文章,可以看一下。
akira
2016-03-22 15:37:23 +08:00
@stackboom 现在他的问题不就是更新缓存前出现脏数据了么
caoyue
2016-03-22 16:54:57 +08:00
如果需要主从架构下的强一致性,还要缓存实时更新,同时还考虑效率,那太难了~

这方面没什么经验,瞎扯一下=-=
如果发生在写数据成功之前,锁就好了吧
如果是主从同步延迟导致的脏数据,有点头疼,只能在修修补补了:
1. 要是严格要求强一致,用同步模式,完全同步成功了再返回可以解决,但是性能……银行这种倒是可以这么干
2. 如果短时间的缓存脏数据可接受,做个队列定时更新脏数据
3. 多主方案,根据 id 保证同一份数据的操作放在同一个服务上
4. 不要把这些放在主从架构上,在之上构建一个中间层
5. 强行把部分操作路由到主库——好吧这种感觉很奇怪
mhycy
2016-03-22 17:03:01 +08:00
同意楼上关于先写入后淘汰缓存的做法,不这么做的原因是什么?并发写入?
eightqueen
2016-03-22 17:28:48 +08:00
@mhycy @jasontse 如果先写数据再淘汰缓存,一旦第一步成功,第二步失败,那么缓存的数据就是过期的。 @caoyue 谢谢指导,我们目前不想折腾,关键数据直接读主。
mhycy
2016-03-22 19:01:39 +08:00
@eightqueen
反过来道理一样,缓存淘汰失败,写入成功那么缓存还是过期的
eightqueen
2016-03-22 20:23:31 +08:00
@mhycy 你觉得两件事哪个失败的概率高?
mhycy
2016-03-22 20:42:20 +08:00
二次淘汰好了。。
calease
2016-03-23 00:04:11 +08:00
写入 DB 成功前缓存里的根本不是脏数据。
写入 DB 成功后缓存里的数据才是 dirty 需要 invalidate ,
所以当然是写完淘汰。
至于淘汰失败,首先楼主多虑,
该成功的操作就是会成功,
失败了只有可能:
1.程序有 bug ,
2.服务面临瘫痪。
再者缓存应该设 expire 所以就算操作失败也迟早会更新。
最后如果一定要操作成功,
最简单的方法就是 retry ,
设置 retry 上限。
retry 上限到了就该发 email/IM 通知全体服务挂了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/265457

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX