读写数据时,应该先操作缓存,还是先操作数据库呢?这个简单的问题,回答起来并不简单...
关于 数据库 + 缓存 的读写模式,业内较广泛承认的是Facebook提出的模式:Cache Aside Pattern。
对于读请求
这个根本没啥疑问,标准流程如下:
- 先读cache,再读db
- 如果cache hit,则直接返回数据
- 如果cache miss,则访问db,并将数据set回缓存
对于写请求
Cache Aside Pattern建议:
(1)淘汰缓存,而不是更新缓存
(2)先操作数据库,再淘汰缓存
为什么建议淘汰缓存,而不是更新缓存?
如果更新缓存,在并发写时,大概出现数据不一致。
如上图所示,1和2同时发起写请求,1要将数据修改为a,2要将数据修改为b,由于无法包管时序,此时大概出现:
(1)请求1先操作数据库,请求2后操作数据库,数据库终极内容为b
(2)请求2先更新了缓存,请求1后更新缓存,缓冲终极内容为a
数据库与缓存之间的数据不一致。
所以,Cache Aside Pattern建议,淘汰缓存,而不是更新缓存。
为什么建议先操作数据库,再操作缓存?
如果先操作缓存,在读写并发时,大概出现数据不一致。
如上图所示,在1和2并发请求,1修改数据,2读取数据。如果先操作缓存,由于无法包管时序,大概出现:
(1)写请求淘汰了缓存
(2)写请求操作了数据库(主从同步没有完成)
(3)读请求读了缓存(cache miss)
(4)读请求读了从库(读了一个旧数据)
(5)读请求set回缓存(set了一个旧数据)
(6)数据库主从同步完成
导致,数据库与缓存的数据不一致。
所以,Cache Aside Pattern建议,先操作数据库,再操作缓存。
Cache Aside Pattern方案存在什么问题?
如果先操作数据库,再淘汰缓存,大概出现:
(1)修改数据库成功了
(2)淘汰缓存失败了
导致,数据库与缓存的数据不一致。
<hr>关注【老张聊架构】,前迅雷大数据CTO,带你成为百万年薪架构师! |