V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
eightqueen
V2EX  ›  问与答

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

  •  
  •   eightqueen · 2016-03-22 14:55:08 +08:00 · 2792 次点击
    这是一个创建于 2967 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    这方面没什么经验,瞎扯一下=-=
    如果发生在写数据成功之前,锁就好了吧
    如果是主从同步延迟导致的脏数据,有点头疼,只能在修修补补了:
    1. 要是严格要求强一致,用同步模式,完全同步成功了再返回可以解决,但是性能……银行这种倒是可以这么干
    2. 如果短时间的缓存脏数据可接受,做个队列定时更新脏数据
    3. 多主方案,根据 id 保证同一份数据的操作放在同一个服务上
    4. 不要把这些放在主从架构上,在之上构建一个中间层
    5. 强行把部分操作路由到主库——好吧这种感觉很奇怪
    mhycy
        7
    mhycy  
       2016-03-22 17:03:01 +08:00
    同意楼上关于先写入后淘汰缓存的做法,不这么做的原因是什么?并发写入?
    eightqueen
        8
    eightqueen  
    OP
       2016-03-22 17:28:48 +08:00
    @mhycy @jasontse 如果先写数据再淘汰缓存,一旦第一步成功,第二步失败,那么缓存的数据就是过期的。 @caoyue 谢谢指导,我们目前不想折腾,关键数据直接读主。
    mhycy
        9
    mhycy  
       2016-03-22 19:01:39 +08:00
    @eightqueen
    反过来道理一样,缓存淘汰失败,写入成功那么缓存还是过期的
    eightqueen
        10
    eightqueen  
    OP
       2016-03-22 20:23:31 +08:00
    @mhycy 你觉得两件事哪个失败的概率高?
    mhycy
        11
    mhycy  
       2016-03-22 20:42:20 +08:00
    二次淘汰好了。。
    calease
        12
    calease  
       2016-03-23 00:04:11 +08:00
    写入 DB 成功前缓存里的根本不是脏数据。
    写入 DB 成功后缓存里的数据才是 dirty 需要 invalidate ,
    所以当然是写完淘汰。
    至于淘汰失败,首先楼主多虑,
    该成功的操作就是会成功,
    失败了只有可能:
    1.程序有 bug ,
    2.服务面临瘫痪。
    再者缓存应该设 expire 所以就算操作失败也迟早会更新。
    最后如果一定要操作成功,
    最简单的方法就是 retry ,
    设置 retry 上限。
    retry 上限到了就该发 email/IM 通知全体服务挂了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1070 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 18:56 · PVG 02:56 · LAX 11:56 · JFK 14:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.