V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
noble4cc
V2EX  ›  Java

经常面试被问到缓存和 db 数据一致性的问题

  •  
  •   noble4cc · 2020-07-29 11:42:57 +08:00 · 5311 次点击
    这是一个创建于 1580 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如说缓存和数据库保持数据一致性,感觉只要是用缓存,这个一致性永远无法保证实时一致性

    还有问先更新数据库再更新缓存,更新缓存失败了怎么办,感觉使用缓存永远无法保证缓存永远的一致性呀,总会有时间差,要要求强一致性就别用缓存了

    27 条回复    2023-10-31 13:57:38 +08:00
    594duck
        1
    594duck  
       2020-07-29 12:19:44 +08:00
    用 MQ
    gantleman
        2
    gantleman  
       2020-07-29 12:46:58 +08:00
    强一致很简单,在缓存外加把锁把所有请求都挡在外面就强一致了。什么外面的请求不能等需要立即返回,哪就再加个缓存。什么第二个缓存也要强一致!!哪就再加个锁,什么第二个锁外面的请求也不能等???要加第三个缓存!!!有时候我觉得我在做开发,有时候我觉得我在做套娃。套娃就是开发,摸鱼就是真理。
    noble4cc
        3
    noble4cc  
    OP
       2020-07-29 14:01:21 +08:00
    @594duck 只要异步就有时差,无法做到实时一模一样
    Octopvs
        4
    Octopvs  
       2020-07-29 16:10:16 +08:00
    更新完数据库,就删掉缓存,下次访问的时候从数据库获取再更新到缓存
    xkeyideal
        5
    xkeyideal  
       2020-07-29 16:22:07 +08:00
    @Octopvs 也要考虑缓存击穿场景
    DoctorCat
        6
    DoctorCat  
       2020-07-29 16:28:23 +08:00   ❤️ 1
    CAP 到底牺牲哪个,根据业务场景来定了。优先看最终一致性能不能行
    xkeyideal
        7
    xkeyideal  
       2020-07-29 16:34:53 +08:00
    缓存与数据库之间的实时一致性或强一致性应该是无法实现的。
    既然用到了缓存,说明数据的变化不是频繁的或者可以容忍一段时间内的数据不一致,否则缓存就失去了使用的价值。
    缓存数据不应该是永久存在的,应该设置一个过期时间,这样能比较好的解决数据不一致的问题。
    个人理解缓存分为两种,一种是内存级缓存,一种是外部缓存,如 redis 。
    内存级缓存应该不会存在更新失败这么一说。
    外部缓存,更新失败的大部分情况是由于网络问题,但又涉及到多个客户端更新同一份缓存的情况,使用外部缓存尤其要考虑数据的变化频繁程度,否则即使更新成功也会出现缓存是脏数据的情况。

    要不要使用缓存,如何使用缓存,是需要根据业务场景具体对待,有些时候,内存级缓存简单高效,而且不易出错,使用上外部缓存就需要考虑多读多写的场景了。
    8355
        8
    8355  
       2020-07-29 17:10:33 +08:00
    不管是内存 io 还是硬盘 io 都需要时间
    如果是同步要求一致性, 那么为什么要存 db 直接存缓存不就好了吗?
    db 存在的意义就没有了.
    因为要强一致那么就是这个场景和结果.

    你这个问题要么就是没描述清楚条件和约束 要么就是面试官提的伪需求.
    tabris17
        9
    tabris17  
       2020-07-29 17:11:05 +08:00   ❤️ 1
    别问,问就是“最终一致性”
    ZehaiZhang
        10
    ZehaiZhang  
       2020-07-29 17:12:23 +08:00
    加钱升数据库配置吧
    Jooooooooo
        11
    Jooooooooo  
       2020-07-29 17:14:03 +08:00
    保持不了就最终一致

    那最终一致怎么做方案就来了
    eaglewangl37670
        12
    eaglewangl37670  
       2020-07-29 17:28:32 +08:00
    我记得我面试的时候也有很多面试官喜欢问这个问题,我也确实没有给出一个较好的解决方案- -
    lihongming
        13
    lihongming  
       2020-07-29 17:38:06 +08:00 via iPhone
    有些云数据库自带缓存服务,并提供 write-through 缓存模式,可以保证数据更新时缓存也更新。

    不过我觉得这可能就是加了个 trigger
    xupefei
        14
    xupefei  
       2020-07-29 18:04:24 +08:00 via iPhone
    用数据库的 trigger 改缓存,失败就回滚啊,一定能保证一致性。
    CoderGeek
        15
    CoderGeek  
       2020-07-29 18:23:39 +08:00
    要么降低性能做强一致 要么老实的接受 BASE
    keshawnvan
        16
    keshawnvan  
       2020-07-29 19:10:20 +08:00
    不在一个事务,隔离级别也不一样,自然保证不了强一致性。
    realpg
        17
    realpg  
       2020-07-29 23:18:59 +08:00
    最简单的,性能可能渣点
    读锁,然后删缓存,然后更新数据库行,提交释放锁。
    jones2000
        18
    jones2000  
       2020-07-30 00:36:32 +08:00
    这和一台 mysql (这台看成是缓存) 同步到另外一台 mysql 一样, 一般都基于日志同步的, 你增加缓存日志,最后根据缓存日志来同步,基本可以一致的。
    noble4cc
        19
    noble4cc  
    OP
       2020-07-30 11:48:07 +08:00
    @Octopvs 对,这样也行,或者直接更新缓存也行,但是对方会问你更新缓存失败或者淘汰缓存失败怎么办,当然我知道,平时他开发也就是更新缓存
    noble4cc
        20
    noble4cc  
    OP
       2020-07-30 11:58:07 +08:00
    @tabris17 最终一致性还是要查 db,当然缓存在有些业务场景下可以过滤掉大部分流量
    huobazi
        21
    huobazi  
       2020-07-30 16:32:06 +08:00
    号称 9999999 想想为什么涅?
    zichen
        22
    zichen  
       2020-07-30 18:21:48 +08:00
    最稳妥的方式就是写进程写数据库然后删缓存,读进程读缓存失败再读数据库再回写缓存。
    zichen
        23
    zichen  
       2020-07-30 18:24:37 +08:00
    @noble4cc 淘汰缓存失败可以放入消息队列,用定时任务做补偿。
    Octopvs
        24
    Octopvs  
       2020-07-30 20:26:53 +08:00
    @xkeyideal 用布隆过滤器解决击穿
    xkeyideal
        25
    xkeyideal  
       2020-07-31 08:55:23 +08:00
    @Octopvs 这是什么骚操作,从来没听过,能解释一下,请教如何使用
    noble4cc
        26
    noble4cc  
    OP
       2020-07-31 14:25:47 +08:00
    @zichen 对,更新缓存和淘汰缓存都可以,淘汰缓存更方便,但是对方肯定会问你淘汰缓存失败了不就 db 和缓存不一致了吗
    vanpeisi7
        27
    vanpeisi7  
       2023-10-31 13:57:38 +08:00
    @Octopvs 多个线程同时更新,A 和 B 都更新这种问题也不行。1.A 获取缓存 ; 2.B 获取缓存; 3.B 更新数据库、删除缓存; 4.A 更新数据库(用的数据是早先从缓存获取的),删除缓存
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3408 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 11:50 · PVG 19:50 · LAX 03:50 · JFK 06:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.