缓存设计 - 互联网最佳实践Cache Aside Pattern
What
Cache Aside Pattern翻译过来是旁路缓存方案的经验实践,这个实践分为读实践、写实践。
How
读实践:
- 先读缓存,再读数据库
- 如果cache hit,则直接返回cache数据
- 如果cache miss,则访问db,并将数据set回缓存,然后返回。
写实践:
先操作数据库写,再淘汰缓存(这里淘汰缓存是删除,而不是更新)
Why
-
写实践中,Cache Aside Pattern为什么是淘汰缓存,而不是更新缓存?
答:如果是更新缓存,在并发写时,可能出现数据不一致。
如上图所示,如果采用set缓存。在1和2两个并发写发生时,由于无法保证时序,此时不管先操作缓存还是先操作数据库,都可能出现:
(1)请求1先操作数据库,请求2后操作数据库
(2)请求2先set了缓存,请求1后set了缓存
导致,数据库与缓存之间的数据不一致。相同的场景如果是delete则不会有此问题。
所以,Cache Aside Pattern建议,delete缓存,而不是set缓存。 -
写实践中,Cache Aside Pattern为什么建议先操作数据库,再操作缓存?
答:如果先操作缓存,在读写并发时,可能出现数据不一致。
如上图所示,如果先操作缓存。在1和2并发读写发生时,由于无法保证时序,可能出现:
(1)写请求淘汰了缓存
(2)写请求操作了数据库(主从同步没有完成)
(3)读请求读了缓存(cache miss)
(4)读请求读了从库(读了一个旧数据)
(5)读请求set回缓存(set了一个旧数据)
(6)数据库主从同步完成
导致,数据库与缓存的数据不一致。所以,Cache Aside Pattern建议,先操作数据库,再操作缓存。
Drawback
然而,Cache Aside Pattern方案并不是完美无缺的,那么Cache Aside Pattern存在什么问题呢?
- 如果先操作数据库,再淘汰缓存,如果数据库操作成功,但是淘汰缓存失败。此时数据库和缓存数据不一致。
个人见解:这里个人觉得可以使用重试的方法,在淘汰缓存的时候,如果失败,则重试一定的次数。如果失败一定次数还不行,那就是其他原因了。比如说redis故障、内网出了问题。
Refer
- https://www.jianshu.com/p/3613d55fb843