举个实际的例子。为了减少对数据库的读操作,我们决定对部分数据加一层 cache。比如判断某 object是否为空,相应数量等等。
我的实现方式是每次数据库commit之后更新cache以防止脏数据,而且不用担心expiration的问题。如果不能hit cache, 我们就去查数据库,同时更新 cache。
我同事对此表示不同意,他的意见是 cache 本来就是性能和数据正确性之间的妥协。所以他觉得我的实现方式其实就是代替数据库,他更倾向设置一个很短的 expiration 时间,并且不去实现 after commit 的 hook,他觉得这样才是正确的使用 cache 的方法。
请问大家对 cache 的用法有什么看法?
1
Andiry 2015-03-31 02:32:28 +08:00
两种都可以。你同事的做法实现上简单一些,看实际需求了。
|
2
Lamian OP 我其实已经实现了,他想让我改。捂脸
|
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也无所谓 需要分开讨论 |
4
Lamian OP 都是单个string,int,boolean这样的数据,基本不吃内存。因为是面对企业的数据,所以我实现的时候把 consistent放在了第一位。具体的预期很难估计,因为这个是老系统,又刚给 server装上 new relic,统计不全面,只能边改边看
|
6
monkeylyf 2015-03-31 03:08:46 +08:00
@Lamian 那就是你和你同事对这个service的consistency的理解不同 去和他/她聊聊吧. 不考虑expiration 的问题(不expire真的大丈夫吗?如果数据量小 cache的意义不大 如果数据量大 不expire感觉要一把汗啊 最好去测一下真实数据)你的做法没啥问题
|
7
ncisoft 2015-03-31 03:50:57 +08:00 via iPad
如果Cache不可信,加cache干啥,过期时间再短也是自欺欺人,你那同事想多了。只是要注意程序以外的地方直接修改数据库,或直接修改cache,这样会造成数据不一致,都跟过期设置无关。可从审计角度考虑问题
|
9
firstway 2015-03-31 05:35:31 +08:00
实在忍不住要回复了。。。。。。。
“cache 本来就是性能和数据正确性之间的妥协”,这个是错误的,他似乎认为用到cache就一定会引起inconsistency,参见CPU和OS kernel里的cache。 什么叫“其实就是代替数据库”,难道我加了一层封装,下层数据库就没了?? cache本身只是概念,怎么做其实是实现层面的东西。 我支持楼主的做法,其实可以考虑这样的,就是 commit 之后,将原cache里对应KV清空,而不是update。这个取决你们场景里,新数据马上被访问的概率多大。 楼主同事要么是调书袋理解不到位,要么是为了反对而反对。 |
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 |
11
Lamian OP @firstway 组里另外一个工程师也要我把 after commit 的东西去掉。我已经默默回去重构了,顺便准备简历面试什么的。不过这帖子的意义其实也是想看看大家对如何使用 cache 的看法什么的
|
14
puncsky 2015-03-31 07:30:49 +08:00 1
Facebook TAO 把 cache 用得出神入化,也值得一读。
|
15
tabris17 2015-03-31 09:36:07 +08:00
还是一句话,看你的应用场景,如果数据一致性要求高,则采用前者,否则使用后者。
抛开应用场景谈缓存策略都是耍流氓 |
17
xinyewdz 2015-03-31 10:07:22 +08:00
其实这两种做法合起来是最好的实现,长时间不访问的数据会expiration,减少内存占用。只cache热点数据。
|
18
firstway 2015-03-31 10:35:32 +08:00
@xinyewdz 作者其实有expiration,只是时间比较长,他们争论之处在于commit 的 hook是否需要,也就是一致性需不需要保证。
|
19
mahone3297 2015-03-31 10:38:07 +08:00
|
20
Lamian OP 不要歪楼啊各位...只想借这个机会讨论一下各种那个cache的策略而已- -
|
21
kn007 2015-03-31 11:24:58 +08:00
mark。
看场景吧。 |
22
feilaoda 2015-03-31 12:14:53 +08:00
cache设置一个很短的expiration是一个很诡异的用法,只有在特殊的场景才使用
通过设置很短的expiration来达到cache数据的一致性,这个也是天才才想到的方法 |
23
sujin190 2015-03-31 12:26:08 +08:00
如果commit后写cache会增加很多复杂性和不可控性吧,如果有很多系统都使用这些数据,这样似乎很难控制啊,好吧,我一直以为cache只是用来减少数据库操作次数的和时间的
|
24
clino 2015-03-31 12:40:01 +08:00
我倾向于楼主的做法,因为这样访问到的数据比较准确
不过主要看对数据的准确程度是不是有要求,如果没有的话,倒是可以用第二种 |
25
vivisidea 2015-03-31 13:40:59 +08:00 2
个人更倾向于 DB commit 后 更新/清空 cache 对应的 key 的做法
设置一个很短的过期时间,多短的时间算是“很短”呢? 长了数据不一致问题会比较明显,短了 cache hit rate 降低,cache 就没啥意义了 |
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操作? |
27
oobleck 2015-03-31 15:21:22 +08:00
两种方式都有道理
你同事的做法是一般是用户的 cache,由于通讯成本比较高,所以愿意在正确性上做一定妥协,比如浏览器的 cache 但是作为服务的提供方,数据正确应该需要保证的,并且也是可以实现的。除非数据正确性不太重要或者服务进程和数据库之间通信成本实在太高,否则没必要代替用户去做这个妥协。 楼主的 cache 实现也不常见,cache 是为读服务的,所以一般常见的做法是写之前清 cache,读 cache miss 后,从数据库读出来再写 cache |
28
julyclyde 2015-03-31 15:31:23 +08:00
你这个其实和mysql query cache类似了
不过现在不提倡用query cache,因为清理次数太多实际上根本cache不了什么 |
29
wanjun 2015-03-31 16:09:12 +08:00
更新不频繁的数据,cache 时间长点,不考虑更新,实在要更新,手动flush
更新频繁,访问量小就不要缓存啦。 更新频繁,访问量大,直接用 redis 这样的内存数据库吧 |
30
justfly 2015-03-31 16:24:02 +08:00
说说个人的做法
读 不命中设置cache;改 清除cache 关于过期:设置cache的占用内存,达到上限缓存中理论最旧数据可以被挤出去,这样最终会导致只有热数据在cache中,个人认为这是内存和性能综合考虑的最优解。 |
31
alexapollo 2015-03-31 20:46:11 +08:00
读:不命中则读db,并设置cache
写:先写入cache,然后异步更新db over,不明白有什么可以争论的点 |
32
ryd994 2015-03-31 23:09:17 +08:00 via Android
@alexapollo 完全不能over。writeback只是各种缓存策略之一罢了。不考虑应用场景就让别人上writeback,这是耍流氓。而且你这个策略也完全没考虑多线程。naive
|
33
alexapollo 2015-03-31 23:12:40 +08:00
@ryd994 一般都这么搞呀。如果不用这个那干嘛不上个redis或memcache就好了,这个策略多线程顶多加个锁不就结了。。。
|
34
ryd994 2015-03-31 23:20:48 +08:00 via Android 1
@alexapollo 用锁还是cow,加锁让谁加,这些都是问题。writethrough对这个问题就好解决得多。writeback还有异常时丢数据的事情。一般只是你身边一般而言吧。银行业务和微博,这就是两个极端,要性能还是要一致。微博偶然掉点数据根本不算事。
|
35
saberlion 2015-03-31 23:24:47 +08:00 via Android
状态的数据类似于redis实现session的用你同事的策略,页面渲染什么的不频繁更新用你的策略。
|
36
alexapollo 2015-04-01 00:12:04 +08:00
@ryd994 金融的是不能这么搞,但一般的互联网场景都可以。金融应该算少数啦。。
|