缓存,究竟是淘汰,还是修改?(2/14)

修改 value 的成本,对比一次 cache miss 的代价——三个案例算到底

缓存实践第 2 课封面:缓存架构与实践02:缓存,究竟是淘汰,还是修改?

修改 value 的成本,对比一次 cache miss 的代价——三个案例算到底

《缓存架构与实践》第 2 篇:缓存,究竟是淘汰,还是修改。

允许cache miss的场景,不管是memcache还是redis,当被缓存的内容变化时,是修改缓存,还是淘汰缓存?这是今天将要讨论的话题。

KV缓存都缓存了一些什么数据?

答:

(1)朴素类型的数据,例如:int

(2)序列化后的对象,例如:User实体,本质是binary

(3)文本数据,例如:json或者html

(4)…

淘汰缓存中的这些数据,修改缓存中的这些数据,有什么差别?

答:

(1)淘汰某个key,操作简单,直接将key置为无效,但下一次该key的访问会cache miss

(2)修改某个key的内容,逻辑相对复杂,但下一次该key的访问仍会cache hit

可以看到,差异仅仅在于一次cache miss。

缓存中的value数据一般是怎么修改的?

答:

(1)朴素类型的数据,直接set修改后的值即可

(2)序列化后的对象:一般需要先get数据,反序列化成对象,修改其中的成员,再序列化为binary,再set数据

(3)json或者html数据:一般也需要先get文本,parse成dom树对象,修改相关元素,序列化为文本,再set数据

结论:对于对象类型,或者文本类型,修改缓存value的成本较高,一般选择直接淘汰缓存。

对于朴素类型的数据,究竟应该修改缓存,还是淘汰缓存?

答:仍然视情况而定。

案例1:

假设,缓存里存了某一个用户uid=123的余额是money=100元,业务场景是,购买了一个商品pid=456。

分析:如果修改缓存,可能需要:

(1)去db查询pid的价格是50元

(2)去db查询活动的折扣是8折(商品实际价格是40元)

(3)去db查询用户的优惠券是10元(用户实际要支付30元)

(4)从cache查询get用户的余额是100元

(5)计算出剩余余额是100 – 30 = 70

(6)到cache设置set用户的余额是70

为了避免一次cache miss,需要额外增加若干次db与cache的交互,得不偿失。

结论:此时,应该淘汰缓存,而不是修改缓存。

案例2:

假设,缓存里存了某一个用户uid=123的余额是money=100元,业务场景是,需要扣减30元。

分析:如果修改缓存,需要:

(1)从cache查询get用户的余额是100元

(2)计算出剩余余额是100 – 30 = 70

(3)到cache设置set用户的余额是70

为了避免一次cache miss,需要额外增加若干次cache的交互,以及业务的计算,得不偿失。

结论:此时,应该淘汰缓存,而不是修改缓存。

案例3:

假设,缓存里存了某一个用户uid=123的余额是money=100元,业务场景是,余额要变为70元。

分析:如果修改缓存,需要:

(1)到cache设置set用户的余额是70

修改缓存成本很低。

结论:此时,可以选择修改缓存。当然,如果选择淘汰缓存,只会额外增加一次cache miss,成本也不高。

总结

允许cache miss的KV缓存写场景:

大部分情况,修改value成本会高于“增加一次cache miss”,因此应该淘汰缓存

如果还在纠结,总是淘汰缓存,问题也不大

任何脱离分析的技术方案都是耍流氓。

检验一下

检索练习 · 淘汰与修改的差异
淘汰某个 key 与修改某个 key 的内容,差异在于什么?

检索练习 · 对象与文本类型
对于对象类型或文本类型的缓存数据,一般选择?

检索练习 · 案例判断
缓存了用户余额,业务要扣减 30 元(需先 get 余额、计算、再 set),应该选择?

检索练习 · 通用建议
如果还在纠结淘汰还是修改,原文的建议是?

淘汰还是修改定了,那写操作时先动缓存还是先动数据库?第 3 篇,把两个方向的原子性破坏场景都推演一遍。

知其然,知其所以然。思路比结论更重要。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

京ICP备2025137728号-3