讨论一下 cache 的用法 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Lamian
V2EX    数据库

讨论一下 cache 的用法

  •  
  •   Lamian 2015-03-31 01:48:08 +08:00 3152 次点击
    这是一个创建于 3852 天前的主题,其中的信息可能已经有所发展或是发生改变。

    举个实际的例子。为了减少对数据库的读操作,我们决定对部分数据加一层 cache。比如判断某 object是否为空,相应数量等等。

    我的实现方式是每次数据库commit之后更新cache以防止脏数据,而且不用担心expiration的问题。如果不能hit cache, 我们就去查数据库,同时更新 cache。

    我同事对此表示不同意,他的意见是 cache 本来就是性能和数据正确性之间的妥协。所以他觉得我的实现方式其实就是代替数据库,他更倾向设置一个很短的 exiration 时间,并且不去实现 after commit 的 hook,他觉得这样才是正确的使用 cache 的方法。

    请问大家对 cache 的用法有什么看法?

    36 条回复    2015-04-01 00:12:04 +08:00
    Andiry
        1
    Andiry  
       2015-03-31 02:32:28 +08:00
    两种都可以。你同事的做法实现上简单一些,看实际需求了。
    Lamian
        2
    Lamian  
    OP
       2015-03-31 02:36:03 +08:00
    我其实已经实现了,他想让我改。捂脸
    monkeylyf
        3
    monkeylyf  
       2015-03-31 02:38:12 +08:00   1
    对加了cache后的db operation下降有什么预期吗 数据量是多少 你的做法就是把数据库装进 cache(memory) 如果不expire的话会吃掉多少内存?
    你们的use case对数据本身是什么要求? 如果是因为cache inconsistent data会有什么影响?我司有些服务是要求data 一定要consistent 宁可牺牲performance 有些是轻微inconsistent也无所谓 需要分开讨论
    Lamian
        4
    Lamian  
    OP
       2015-03-31 02:47:00 +08:00
    都是单个string,int,boolean这样的数据,基本不吃内存。因为是面对企业的数据,所以我实现的时候把 consistent放在了第一位。具体的预期很难估计,因为这个是老系统,又刚给 server装上 new relic,统计不全面,只能边改边看
    Lamian
        5
    Lamian  
    OP
       2015-03-31 02:47:37 +08:00
    monkeylyf
        6
    monkeylyf  
       2015-03-31 03:08:46 +08:00
    @Lamian 那就是你和你同事对这个service的consistency的理解不同 去和他/她聊聊吧. 不考虑expiration 的问题(不expire真的大丈夫吗?如果数据量小 cache的意义不大 如果数据量大 不expire感觉要一把汗啊 最好去测一下真实数据)你的做法没啥问题
    ncisoft
        7
    ncisoft  
       2015-03-31 03:50:57 +08:00 via iPad
    如果Cache不可信,加cache干啥,过期时间再短也是自欺欺人,你那同事想多了。只是要注意程序以外的地方直接修改数据库,或直接修改cache,这样会造成数据不一致,都跟过期设置无关。可从审计角度考虑问题
    Lamian
        8
    Lamian  
    OP
       2015-03-31 04:51:16 +08:00
    @monkeylyf 其实有 expiration 的,12个小时 - -
    firstway
        9
    firstway  
       2015-03-31 05:35:31 +08:00
    实在忍不住要回复了。。。。。。。
    “cache 本来就是性能和数据正确性之间的妥协”,这个是错误的,他似乎认为用到cache就一定会引起inconsistency,参见CPU和OS kernel里的cache。
    什么叫“其实就是代替数据库”,难道我加了一层封装,下层数据库就没了??
    cache本身只是概念,怎么做其实是实现层面的东西。

    我支持楼主的做法,其实可以考虑这样的,就是 commit 之后,将原cache里对应KV清空,而不是update。这个取决你们场景里,新数据马上被访问的概率多大。

    楼主同事要么是调书袋理解不到位,要么是为了反对而反对。
    puncsky
        10
    puncsky  
       2015-03-31 06:21:35 +08:00   6
    KV Cache的本质是为了 Reduce latency for accessing active data,把常用数据的数据库的O(logn)的读写和复杂的查询变成O(1)的读写,cache的设计有很多pattern,常见的有 read-through/write-through(or write-back) 和 cache aside.

    在分布式系统中,这些 pattern 的组合都是 consistency, availability, partition tolerance 之间的 trade-off,要根据你的业务需求具体选择。

    ## read-through/write-through(or write-back)

    - Read-through: clients 和 databases 之间加一层 cache layer,clients 不直接访问数据库,clients 通过 cache 间接访问数据库。读的时候 cache 里面没有东西则从database更新再返回,有则直接返回。

    - Write-through: clients 先写数据到 cache,cache 更新 database,只有 database 最终更新了,操作才算完成。

    - Write-around: clients 写的时候绕过 cache 直接写数据库。

    - Write-back: clients 先写数据到 cache,先返回。回头将 cache 异步更新到 database.

    一般来讲 write-back 是最快的

    ## cache aside pattern

    Cache 不支持 Read through / write through 的时候用 Cache aside pattern https://msdn.microsoft.com/en-us/library/dn589799.aspx
    Lamian
        11
    Lamian  
    OP
       2015-03-31 06:50:15 +08:00
    @firstway 组里另外一个工程师也要我把 after commit 的东西去掉。我已经默默回去重构了,顺便准备简历面试什么的。不过这帖子的意义其实也是想看看大家对如何使用 cache 的看法什么的
    Andiry
        12
    Andiry  
       2015-03-31 07:01:33 +08:00
    @Lamian 都已经做出来了还有重构的道理?先跑了再说,有问题再改。他们觉得应该按他们的做法,那就拿出实际东西来做对比。
    Lamian
        13
    Lamian  
    OP
       2015-03-31 07:12:28 +08:00
    @Andiry Review 阶段,不给我过啊,只能回去改了。这都是小事,主要是看看大家对 cache 的看法什么的
    puncsky
        14
    puncsky  
       2015-03-31 07:30:49 +08:00   1
    Facebook TAO 把 cache 用得出神入化,也值得一读。
    tabris17
        15
    tabris17  
       2015-03-31 09:36:07 +08:00
    还是一句话,看你的应用场景,如果数据一致性要求高,则采用前者,否则使用后者。

    抛开应用场景谈缓存策略都是耍流氓
    GuangXiN
        16
    GuangXiN  
       2015-03-31 10:03:42 +08:00 via Android
    @firstway 二楼真相
    xinyewdz
        17
    xinyewdz  
       2015-03-31 10:07:22 +08:00
    其实这两种做法合起来是最好的实现,长时间不访问的数据会expiration,减少内存占用。只cache热点数据。
    firstway
        18
    firstway  
       2015-03-31 10:35:32 +08:00
    @xinyewdz 作者其实有expiration,只是时间比较长,他们争论之处在于commit 的 hook是否需要,也就是一致性需不需要保证。
    mahone3297
        19
    mahone3297  
       2015-03-31 10:38:07 +08:00
    @Lamian 找你们老大,再review下看看?做个中间人?
    其实lz的做法,会更保障数据的准确,一致性。不过可能会降低性能。
    我觉得,也要看你们的业务场景。。。
    Lamian
        20
    Lamian  
    OP
       2015-03-31 10:50:38 +08:00
    不要歪楼啊各位...只想借这个机会讨论一下各种那个cache的策略而已- -
    kn007
        21
    kn007  
       2015-03-31 11:24:58 +08:00
    mark。
    看场景吧。
    feilaoda
        22
    feilaoda  
       2015-03-31 12:14:53 +08:00
    cache设置一个很短的expiration是一个很诡异的用法,只有在特殊的场景才使用

    通过设置很短的expiration来达到cache数据的一致性,这个也是天才才想到的方法
    sujin190
        23
    sujin190  
       2015-03-31 12:26:08 +08:00
    如果commit后写cache会增加很多复杂性和不可控性吧,如果有很多系统都使用这些数据,这样似乎很难控制啊,好吧,我一直以为cache只是用来减少数据库操作次数的和时间的
    clino
        24
    clino  
       2015-03-31 12:40:01 +08:00
    我倾向于楼主的做法,因为这样访问到的数据比较准确

    不过主要看对数据的准确程度是不是有要求,如果没有的话,倒是可以用第二种
    vivisidea
        25
    vivisidea  
       2015-03-31 13:40:59 +08:00   2
    个人更倾向于 DB commit 后 更新/清空 cache 对应的 key 的做法

    设置一个很短的过期时间,多短的时间算是“很短”呢?
    长了数据不一致问题会比较明显,短了 cache hit rate 降低,cache 就没啥意义了
    laoyur
        26
    laoyur  
       2015-03-31 13:58:04 +08:00
    个人赞同楼主的做法,只是cache expiration time需要根据实际情况确定,或者做成可配置的之类。

    另外对“DB commit 后 清空 cache”的做法表示不能理解。read from DB 需要add cache,那凭什么write to DB后居然是delete cache?write操作的优先级居然还抵不上一个read操作?
    oobleck
        27
    oobleck  
       2015-03-31 15:21:22 +08:00
    两种方式都有道理

    你同事的做法是一般是用户的 cache,由于通讯成本比较高,所以愿意在正确性上做一定妥协,比如浏览器的 cache

    但是作为服务的提供方,数据正确应该需要保证的,并且也是可以实现的。除非数据正确性不太重要或者服务进程和数据库之间通信成本实在太高,否则没必要代替用户去做这个妥协。

    楼主的 cache 实现也不常见,cache 是为读服务的,所以一般常见的做法是写之前清 cache,读 cache miss 后,从数据库读出来再写 cache
    julyclyde
        28
    julyclyde  
       2015-03-31 15:31:23 +08:00
    你这个其实和mysql query cache类似了
    不过现在不提倡用query cache,因为清理次数太多实际上根本cache不了什么
    wanjun
        29
    wanjun  
       2015-03-31 16:09:12 +08:00
    更新不频繁的数据,cache 时间长点,不考虑更新,实在要更新,手动flush

    更新频繁,访问量小就不要缓存啦。

    更新频繁,访问量大,直接用 redis 这样的内存数据库吧
    justfly
        30
    justfly  
       2015-03-31 16:24:02 +08:00
    说说个人的做法

    读 不命中设置cache;改 清除cache

    关于过期:设置cache的占用内存,达到上限缓存中理论最旧数据可以被挤出去,这样最终会导致只有热数据在cache中,个人认为这是内存和性能综合考虑的最优解。
    alexapollo
        31
    alexapollo  
       2015-03-31 20:46:11 +08:00
    读:不命中则读db,并设置cache
    写:先写入cache,然后异步更新db

    over,不明白有什么可以争论的点
    ryd994
        32
    ryd994  
       2015-03-31 23:09:17 +08:00 via Android
    @alexapollo 完全不能over。writeback只是各种缓存策略之一罢了。不考虑应用场景就让别人上writeback,这是耍流氓。而且你这个策略也完全没考虑多线程。naive
    alexapollo
        33
    alexapollo  
       2015-03-31 23:12:40 +08:00
    @ryd994 一般都这么搞呀。如果不用这个那干嘛不上个redis或memcache就好了,这个策略多线程顶多加个锁不就结了。。。
    ryd994
        34
    ryd994  
       2015-03-31 23:20:48 +08:00 via Android   1
    @alexapollo 用锁还是cow,加锁让谁加,这些都是问题。writethrough对这个问题就好解决得多。writeback还有异常时丢数据的事情。一般只是你身边一般而言吧。银行业务和微博,这就是两个极端,要性能还是要一致。微博偶然掉点数据根本不算事。
    saberlion
        35
    saberlion  
    &nsp;  2015-03-31 23:24:47 +08:00 via Android
    状态的数据类似于redis实现session的用你同事的策略,页面渲染什么的不频繁更新用你的策略。
    alexapollo
        36
    alexapollo  
       2015-04-01 00:12:04 +08:00
    @ryd994 金融的是不能这么搞,但一般的互联网场景都可以。金融应该算少数啦。。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     856 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 21:32 PVG 05:32 LAX 14:32 JFK 17:32
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86