Cache Aside Pattern 即旁路缓存是缓存方案的经验实践,这个实践又分读实践,写实践

对于读请求

  • 先读cache,再读db

  • 如果,cache hit,则直接返回数据

  • 如果,cache miss,则访问db,并将数据set回缓存

Cache Aside Pattern-LMLPHP

如上图:

(1)先从cache中尝试get数据,结果miss了

(2)再从db中读取数据,从库,读写分离

(3)最后把数据set回cache,方便下次读命中

对于写请求

  • 淘汰缓存,而不是更新缓存

  • 先操作数据库,再淘汰缓存

Cache Aside Pattern-LMLPHP

如上图:

 (1)第一步要操作数据库,第二步操作缓存

(2)缓存,采用delete淘汰,而不是set更新

Cache Aside Pattern为什么建议淘汰缓存,而不是更新缓存?如果更新缓存,在并发写时,可能出现数据不一致。

Cache Aside Pattern-LMLPHP

如上图所示,如果采用set缓存。

在1和2两个并发写发生时,由于无法保证时序,此时不管先操作缓存还是先操作数据库,都可能出现:

(1)请求1先操作数据库,请求2后操作数据库

(2)请求2先set了缓存,请求1后set了缓存

导致,数据库与缓存之间的数据不一致。

所以,Cache Aside Pattern建议,delete缓存,而不是set缓存

Cache Aside Pattern为什么建议先操作数据库,再操作缓存?

如果先操作缓存,在读写并发时,可能出现数据不一致。

Cache Aside Pattern-LMLPHP

如上图所示,如果先操作缓存。

在1和2并发读写发生时,由于无法保证时序,可能出现:

(1)1.1 写请求淘汰了缓存

(2)1.2 写请求操作了数据库(主从同步没有完成)

(3)2.1 读请求读了缓存(cache miss)

(4)2.2 读请求读了从库(读了一个旧数据)

(5)2.3 读请求set回缓存(set了一个旧数据)

(6)1.3 数据库主从同步完成

导致,数据库与缓存的数据不一致。

所以,Cache Aside Pattern建议,先操作数据库,再操作缓存

先操作数据库再操作缓存, 在读写并发时,也可能出现数据不一致。

Cache Aside Pattern-LMLPHP

如上图所示,如果先操作数据库。

(1)1.1 读请求读了缓存(cache miss)

(2)1.2 读请求读了从库(读了一个旧数据)

(3)2.1 写请求操作了数据库

(4)2.2 写请求淘汰缓存(cache miss 淘汰跟没淘汰一样)

(5)1.3 读请求set回缓存(set了一个旧数据)

(6)2.3 数据库主从同步完成

导致,数据库与缓存的数据不一致

但是:先淘汰缓存再更新数据库方案中,写请求 淘汰缓存后 被 读请求 set回一个旧数据,这种并发出现的几率很大。 而: 先更新数据库再淘汰缓存方案中,读请求 在写请求之前读了数据且data miss,又要在写请求之后set缓存, 这种几率很小。 所以:Cache Aside Pattern建议,先操作数据库,再操作缓存。

Cache Aside Pattern方案存在什么问题?

:如果先操作数据库,再淘汰缓存,在原子性被破坏时:

(1)修改数据库成功了

(2)淘汰缓存失败了

导致,数据库与缓存的数据不一致。

参考:58沈剑 架构师之路

 

04-29 00:08