zhongpingjing
0D
V2EX  ›  Java

你们引入缓存中间件,会去解决数据库缓存双写一致性的问题吗

  •  1
     
  •   zhongpingjing · Jun 3, 2021 · 5351 views
    This topic created in 1983 days ago, the information mentioned may be changed or developed.
    看了一篇博文了解了一些相关的内容,了解到引起不一致性的原因:
    先删缓存,再更新 DB (这种策略应该没有人用?)
    先更新 DB,再删缓存(这种发生不一致性的概率虽然可以忽略不计,但是是否需要去防止?)
    先更新 DB,然后删除缓存失败(真的会发生删除缓存失败吗?网络原因?)
    DB 主从复制的延迟造成不一致
    。。。

    解决这个双写一致性问题,需要双删和重试。感觉这种方式代价有点大啊。
    在实际生产中,会这样去解决吗?有没有更好的办法?
    29 replies  •  2021-06-15 17:55:02 +08:00
    wqhui
    wqhui
    Jun 3, 2021
    1
    看业务是不是要求强一致性,还是说最终一致性也可以,强一致性的话代价肯定是大的了
    BBCCBB
    BBCCBB
    Jun 3, 2021
    2
    没有解决.. 不能容忍的地方我们都查 db.

    只要两个地方没有事务. 总是有不一致的窗口存在.
    vindac
    vindac
    Jun 3, 2021
    3
    我们都是缓存定时淘汰,有个服务去更新缓存。。
    zhongpingjing
    zhongpingjing
    OP
    Jun 3, 2021
    4
    @vindac 意思是你们的业务服务自身不会去更新缓存是吗,那如果缓存过期了,会去查 DB 呢还是直接返回 null ?去查 DB 的话,查完会把结果放到缓存中吗?
    abigeater
    abigeater
    Jun 3, 2021
    5
    业务操作对缓存操作不直接写到 DB
    服务定时将缓存写到 DB
    读取从缓存读取 没有数据从 DB 读取后写到缓存
    zhongpingjing
    zhongpingjing
    OP
    Jun 3, 2021
    6
    @vindac 专门的更新缓存服务,那要如何定位到失效缓存,如何更新它啊,比如缓存 A 过期了,缓存服务就需要去 DB 拉取数据放到缓存中,如何发现缓存 A 失效了,并及时更新它
    raaaaaar
    raaaaaar
    Jun 3, 2021 via Android
    7
    定时是个思想,大概可以参考下 cache 和内存的做法?没命中时再装载到 cache 里,满了就置换,根据修改位先写会再换什么的
    zhongpingjing
    zhongpingjing
    OP
    Jun 3, 2021
    8
    @abigeater 这样有可能丢失数据
    zhongpingjing
    zhongpingjing
    OP
    Jun 3, 2021
    9
    @raaaaaar 有点听不懂大佬在讲什么[笑哭]
    InkAndBanner
    InkAndBanner
    Jun 3, 2021
    10
    @abigeater 从 DB 读 写到缓存里面不好吗?
    potatowish
    potatowish
    Jun 3, 2021 via iPhone❤️1
    11
    1.先更新 DB,再删缓存
    2.订阅 binlog 日志去单独做更新,比如 canal
    fkname
    fkname
    Jun 3, 2021
    12
    一般有缓存时间兜底
    lsp7572
    lsp7572
    Jun 3, 2021
    13
    延时双删了解下
    zhch602
    zhch602
    Jun 3, 2021
    14
    @lsp7572 别误导人了,延迟双删也就面试八股文用用,真正生产中使用就是找死
    iyaozhen
    iyaozhen
    Jun 3, 2021
    15
    @zhch602 咦,为啥。比较简单有效
    Croxx
    Croxx
    Jun 3, 2021 via iPhone
    16
    leafre
    leafre
    Jun 3, 2021
    17
    删除缓存失败,那就补偿,直到成功为止,单机不一致解决
    主从不一致使用选择性读主解决
    ryd994
    ryd994
    Jun 4, 2021 via Android
    18
    双删和后删有什么区别呢?
    如果你速度快,别人速度慢,你更新完了别人再去取数据。和你先更新再删缓存又有什么区别?
    如果你速度慢,别人速度快。别人把旧值取了,你再去把旧值再删一遍。

    提供的保证是基本一样的,就是缓存对 db 的延迟一致性。考虑到写入者挂掉的情况,这甚至不是最终一致性。

    你如果要求强一致,那只能用锁了。不那么蛋疼的办法就是:写一个中间件代理。对同一数据的请求由这同一台代理序列化。中间件可以在修改数据库的时候加锁。用本地锁实现了强一致。
    但是现在问题就转移到了如何保证对同一数据的请求总是由同一代理处理的问题。看起来是 hash 一下不难。但是你得考虑代理服务器上线离线的情况。
    bthulu
    bthulu
    Jun 4, 2021❤️1
    19
    不管双删后删, 因网络问题, 都可能导致数据不一致.
    如果需要最终一致性, 操作 db 时, 同时在数据库中标记一下需要更新的缓存, 因与 db 操作在同一数据库, 可以保证这里的强一致性.
    然后再开定时任务从 db 中捞取需要更新缓存的数据, 去更新缓存, 更新成功后, 再清除此更新标记, 更新缓存失败, 不做处理, 等待下一次任务执行周期就行.
    abigeater
    abigeater
    Jun 4, 2021
    20
    @InkAndBanner em..你这里是 从 DB 读,写到缓存吗 还是从 DB 读写到缓存 这个空格分的不够开不知道是哪个意思
    1.从 DB 读,写到缓存:我这用定时服务从缓存写到 DB 那如果从 DB 读 就会有个时间差 定时服务还没写进 DB 时被读取就会拿到旧数据 那数据就不一致了
    2.从 DB 读写缓存:就是这个意思,只是把从缓存写回到 DB 的压力减少
    abigeater
    abigeater
    Jun 4, 2021
    21
    @zhongpingjing 不会丢吧 边界值可以直接写回 DB 后清缓存和删写回队列 其他的都可以走这个流程 一般 DB 崩都是瞬发的请求导致的 在定时服务写回 DB 可以是频繁的不间断的所以写回 DB 队列应该不会造成堵塞(可能,目前我还没遇过堵塞至少)
    lsp7572
    lsp7572
    Jun 4, 2021
    22
    @zhch602 当然是视业务场景而定,你这一句话找死还没我四个字的信息量大好吧。。起码给个例子,我也能学习。。
    xuanbg
    xuanbg
    Jun 4, 2021
    23
    大多数程序员可能没有意识到的是:缓存失效的时序其实并没有辣么重要。假设先读到数据,然后数据被删除,再用这个数据创建了新的数据。在业务上有问题吗?一点问题就没有呀。例如某个客户被删除了,原先基于这个客户的数据失效了吗?并没有啊,所以你们在纠结什么呢?

    所以,先删数据库再删缓存就行了。
    zhch602
    zhch602
    Jun 4, 2021
    24
    @lsp7572
    @iyaozhen
    因为即使用了延迟双删还是有可能不一致,最关键的是 我没听说过哪个业务敢在线上让线程 sleep 个几百毫秒甚至更多
    至于资料,你们随便在 google 上搜延迟双删第一页就有文章,直接放个链接 https://www.cnblogs.com/zhouj-happy/p/12616906.html
    lsp7572
    lsp7572
    Jun 4, 2021
    25
    @zhch602 你发的这文章只是提出了问题,没有解决问题。

    至于你说的 sleep 这个就是业务来决定的

    延时双删就是一定程度可以解决缓存一致性问题的解决方法
    lsp7572
    lsp7572
    Jun 4, 2021
    26
    另外删除操作可以另起线程,这个是业务方可以考量的虽然会增加编码复杂度
    zhch602
    zhch602
    Jun 4, 2021 via Android
    27
    @lsp7572 解决方法就是没有完美的解决方法,要视业务而定,要强一致只能加锁,最终一致的话延迟双删也是下下策
    JasonLaw
    JasonLaw
    Jun 10, 2021
    28
    liian2019
    liian2019
    Jun 15, 2021
    29
    @potatowish 这得单独整一套分布式缓存服务才行,太重了
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   736 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 54ms · UTC 19:38 · PVG 03:38 · LAX 11:38 · JFK 14:38
    ♥ Do have faith in what you're doing.