3种常用的缓存读写策略
QBug Lifelong Learner

以前只是用过Redis作缓存, 缓存和数据库之间怎么舒服怎么来, 今天才发现原来还有缓存模式一说. 下文将从读和写来介绍3种常用缓存读写模式

旁路缓存模式 ( Cache Aside Pattern )

这个模式应该是比较容易想到的, 同时也是比较常用的.

  1. 若缓存存在数据, 则直接返回缓存数据
  2. 若缓存不存在该数据, 则到数据库进行查询并将结果写入缓存

  1. 更新db记录
  2. 删除缓存记录

为什么写操作时要先更新db后删除缓存?

我们假设先删除缓存再更新db, 且有一个查询和一个更新操作. 数据库与缓存存在一个记录old.

假设更新操作已经按照我们的假设删除了缓存old, 正准备更新db为new, 此时查询操作开始, 没命中缓存, 于是从db中查询并更新旧数据old到缓存中, 这个时候更新操作才开始进行更新, 将数据库更新为new.

整个流程下来, 两个操作都顺利完成了任务, 此时数据库数据为更新后的new, 而缓存中为旧数据old. 于是就产生了脏数据, 甚至如果接下来没有写操作或者没有给缓存设置过期时间的话, 这个脏数据会一直脏下去.

那么, 先更新db再删除缓存就没有问题吗?

并不是, 先更新db再删除缓存也存在一定问题.

还是一样我们有两个操作: 查询与写入. 数据库与缓存内容为old. 接下来分为两种情况

1 首先假设写入操作已经更新完db为new, 即将删除缓存. 此时查询操作他来了, 拿了缓存中的old就走了, 查询操作走了后写入操作才来得及将缓存删除. 这就导致了此次查询操作查到的是脏数据.

2 假设查询操作没有命中缓存, 到db中查询结果为old后正打算写入缓存, 这个时候更新操作来了, 光速更新db为new后删除缓存. 更新操作结束后, 查询操作才将查询到的old写入缓存, 于是就出现了缓存为old, 数据库为new的脏数据的情况.

既然如此也存在问题, 那为什么还要这样设计呢?

对于上述2种情况 :

1 首先发生两个操作按照假设的进行的情况概率很低, 而且此时的脏数据只会被读取一次, 是一次性的脏数据, 影响不大.

2 同样的按照假设来的概率很低, 首先db(磁盘)的IO速度是远远小于缓存(内存)的. 于是在查询操作查询db后到写入到缓存中的这段时间, 基本上是不足以给更新操作完成所有动作的, 因此发生的概率很小.

引用缓存更新的套路 | 酷 壳 - CoolShell的一句话

在软件设计上,我们基本上不可能做出一个没有缺陷的设计,就像算法设计中的时间换空间,空间换时间一个道理,有时候,强一致性和高性能,高可用和高性能是有冲突的。软件设计从来都是取舍Trade-Off。

为什么写操作只是删除缓存而不是更新缓存?

Why does Facebook use delete to remove the key-value pair in Memcached instead of updating the Memcached during write request to the backend? - Quora

读写穿透模式 ( Read/Write Through Pattern )

读写穿透模式主要是将缓存作为主体, 将持久化操作交给缓存进行操作, 应用不需要编写持久化操作的代码.

对于应用来说, 缓存以及数据库是透明的, 应用只需要进行查询/写入, 对于不存在缓存中的数据等并不需要进行额外的操作, 例如 : 查询数据时缓存不存在该数据, 由缓存自己从db中查询数据并写入缓存中, 不需要应用自己写入. 这也就减少了应用的代码量, 少了点要操心的事情.

  1. 若命中缓存, 直接返回
  2. 缓存中无该数据, 向db查询, 由缓存将查询结果更新到缓存中.

  1. 若缓存中存在该数据, 直接更新缓存数据, 并由缓存自动更新db
  2. 若缓存中无该数据, 直接更新db.

异步缓存模式 ( Write Behind Pattern )

这种模式和读写穿透模式是差不多的, 比较大的区别在于**”同步”与”异步”**.

异步缓存模式采用的是定时将缓存中需要持久化的数据写入到db中.

这样的设计有一个很明显的问题 : 无法做到强一致性. 因为是定时写入db, 一旦出现缓存更新后, 还没来得及写入db就挂掉了, 此时数据就会出现不一致甚至丢失的情况. 但是带来的好处也是很明显 : 提高了IO速度. 因为每次写入数据时, 不需要立刻写入db, 对于单次数据库操作来说是提高了速度的.

  • Post title:3种常用的缓存读写策略
  • Post author:QBug
  • Create time:2021-06-10 01:20:56
  • Post link:https://q-bug4.github.io//articles/2021/06/10/1623259256672.html
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.