前面几篇关于缓存的文章主要介绍了相关原理,本篇从业务应用角度讲述相关的使用策略。
有兴趣朋友可以关注公众号“架构之道与术”, 获取最新文章。
或扫描如下二维码:
缓存更新策略
被动更新
设置key过期的时间,让其自动失效。
主动更新
更新DB的时候,同时更新缓存。一般业务都是主动更新和被动更新结合使用。
先更新DB,后更新缓存
对于主动更新来说,存在一个问题:你是先更新缓存,后更新DB;还是反过来?
下面分别分析以下2个场景,假设有2个线程,t1, t2:
(1) 先更新缓存,后更新DB。假设有如下的执行系列:
t1更新缓存;
t2读缓存,因为t1把缓存更新了,导致t2没读到。从db中读,然后更新缓存;
t1更新DB。
上述操作系列会导致缓存脏数据。
(2)先更新DB,后更新缓存。假设有如下操作序列:
t1更新DB;
t2更新DB;
t2更新缓存;
t1更新缓存。
上述操作系列同样会导致缓存脏数据。
一句话,无论谁先谁后,只要更新缓存和更新DB不是原子的,就可能导致不一致。只是从实际业务来讲,一般缓存也都是保持“最终一致性“,而不是和DB的强一致性。
并且一般建议先更新DB,再更新缓存,优先保证DB数据正确。
但如果一定要“强一致性“,就不能用上面的解决方案了。有一个解决办法就是不要更新缓存,而是直接删除缓存(让缓存过期),但这会增加缓存的miss率。
缓存更新的实现策略
策略1:业务方(调用者)更新
传统上,更新缓存都是由业务方来做,也就是由调用者负责更新DB和缓存。
策略2:DB中间件监听DB变化,更新缓存
现在有种新的办法就是利用DB中间件监听DB变化(比如阿里的Canal中间件,点评的Puma),从而对缓存进行更新。
这种办法的一个好处就是:把缓存的更新逻辑,和业务逻辑解藕。业务只更新DB,缓存的更新被放在另外一个专门的系统里面。
缓存穿透
所谓“缓存穿透“,就是指某个key,先查cache没查到,再查db也没有查到。
这种key的存在,会导致cache一直没办法命中,压力一直打在db上面。如果访问很高频,可能会压垮DB。
解决办法其实也很简单:当查询DB没查到时,往缓存中写入一个空值(缺省值),这样第2次再查,就不会打到DB上了。
缓存雪崩
所谓“缓存雪崩“,是指缓存的机器挂了,所有请求直接打到DB上面,从而导致DB也挂掉。
这种问题的解决策略,一般有以下2个方面:
(1)提高缓存的HA。比如缓存的主从复制。
(2)对DB的访问实行限流、降级。
关于限流、降级的做法,参见分布式序列的另外一篇文章“服务熔断、降级、限流、异步RPC – HyStrix“。