Redis常见的缓存更新策略有三种,分别是Cache Aside Pattern(旁路缓存模式)、Read/Write Through Pattern(读写穿透模式)以及Write Behind Pattern (异步缓存写入模式)三种。三种模式各有优劣,不存在最佳模式,根据具体的业务场景选择适合自己的缓存读写模式即可。以下将分别介绍三种模式。
Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式,比较适合读请求比较多的场景。
Cache Aside Pattern 中服务端需要同事维系数据库(后文简称db)和缓存(后文简称cache),并且是以db的结果为准。
下面我们来看一下这个策略模式下的缓存读写步骤。
写:
如下图所示:
那么问题来了,为什么是删除cache,而不是更新cache呢?
主要原因有两点:
然后另外一个问题, 在写数据的过程中,能否先删除cache,后更新db呢?
答案可能是不行,因为这样可能会导致造成数据库(db)和缓存(Cache)数据不一致的问题。
举个例子:请求1先写数据A,请求2虽有读数据A的话,就很有可能产生数据不一致性的问题。这个过程可以简单描述为:
这就会导致请求2读取到的是旧值。
那么 如果是在写数据的过程中,先更新db,后删除cache就没有问题了吗?
理论上来说还是可能会出现数据不一致的问题,不过概率非常小,因为缓存的写入速度比数据库的写入速度快很多。
举个例子:请求1先读取数据A,请求2随后写数据A,并且数据A在请求1请求之前不在缓存中的话,也有可能产生数据不一致性的问题。这个过程可以简单描述为:
这就会导致cache中存放的其实是旧值。
现在我们再来分析一下 Cache Aside Pattern 的缺陷。
缺陷1:首次请求数据一定不在cache的问题
解决方法:可以将热点数据提前放入cache中。
缺陷2: 写操作比较频繁的话导致cache中的数据会被频繁删除,这样会影响缓存命中率。
解决方法:
Read/Write Through Pattern 中服务端把 cache 视为主要数据存储,从中读取数据并将数据写入其中。cache 服务负责将此数据读取和写入 db,从而减轻了应用程序的职责。
这种缓存读写策略大家应该也发现了在平时在开发过程中非常少见。抛去性能方面的影响,大概率是因为我们经常使用的分布式缓存 Redis 并没有提供 cache 将数据写入 db 的功能。
写(Write Through):
读(Read Through):
如下图:
Read-Through Pattern 实际只是在 Cache-Aside Pattern 之上进行了封装。在 Cache-Aside Pattern 下,发生读请求的时候,如果 cache 中不存在对应的数据,是由客户端自己负责把数据写入 cache,而 Read Through Pattern 则是 cache 服务自己来写入缓存的,这对客户端是透明的。
和 Cache Aside Pattern 一样, Read-Through Pattern 也有首次请求数据一定不再 cache 的问题,对于热点数据可以提前放入缓存中。
Write Behind Pattern 和 Read/Write Through Pattern 很相似,两者都是由 cache 服务来负责 cache 和 db 的读写。
但是,两个又有很大的不同:Read/Write Through 是同步更新 cache 和 db,而 Write Behind 则是只更新缓存,不直接更新 db,而是改为异步批量的方式来更新 db。
很明显,这种方式对数据一致性带来了更大的挑战,比如 cache 数据可能还没异步更新 db 的话,cache 服务可能就就挂掉了。
这种策略在我们平时开发过程中也非常非常少见,但是不代表它的应用场景少,比如消息队列中消息的异步写入磁盘、MySQL 的 Innodb Buffer Pool 机制都用到了这种策略。
Write Behind Pattern 下 db 的写性能非常高,非常适合一些数据经常变化又对数据一致性要求没那么高的场景,比如浏览量、点赞量。
以上便是对Redis常见的三种缓存更新策略的一个介绍。