Redis 缓存更新策略

缓存能够有效地加速应用的读写速度,因为它基于内存,减少了磁盘 IO 的开销。但它也存在数据不一致的问题,因为缓存层和存储层的数据存在着一定时间窗口的不一致性

给出加入缓存层的结构图:

21

下面介绍三种缓存更新策略,没有最优,只有根据业务场景最合适!!

旁路缓存模式 (Cache Aside Pattern)

旁路缓存模式是平时使用较多的一个读写缓存模式,比较适合于读请求较多的场景

写操作的步骤:

读操作的步骤:

22

问题一:先更新 DB,再删除 Cache,能保证数据一致性吗?

理论上来说还是可能会出现数据不一致的问题,但概率很小,因为删除 Cache 的操作速度快,使 Cache 中和 DB 中数据不一致的时间窗口很短

只有在不一致时间窗口内读数据才会出现数据不一致问题,即:读到旧值,如下图

23

下面举一个数据不一致的例子:线程 1 写数据 A,随后线程 2 读数据 A。正确的情况下线程 2 读到的应该是数据 A 的新值,但如果以下面的顺序执行:

此时线程 2 读到的是数据 A 的旧值

问题二:为什么删除 Cache,而不是更新 Cache?

24

问题三:可以先删除 Cache,后更新 DB 吗?

显然不可以,这样会导致数据不一致的时间窗口变大,进而增加了出现数据不一致问题的概率

25

下面举一个数据不一致的例子:线程 1 写数据 A,随后线程 2 读数据 A。正确的情况下线程 2 读到的应该是数据 A 的新值,但如果以下面的顺序执行:

此时线程 2 读到的是数据 A 的旧值,而且 Cache 存入的也是旧值。如果 Cache 没有设置过期时间且未来一段时间没有新的写操作,那么后面读数据 A 时全都是 Cache 中的旧值!!

缺陷一:首次请求数据不在 Cache 中

缺陷二:写操作频繁会导致 Cache 中数据频繁被删,会影响命中率?

读写穿透 (Read/Write Through Pattern)

核心思想:更新 DB,缓存存在就更新,不存在就不管

读写穿透将 Cache 作为主要的数据存储,从中读取并将数据写入其中,Cache 服务自己负责将此数据读取和写入 DB,从而减轻了程序员的职责

这种模式平时使用很少,大概率因为 Redis 分布式缓存并没有提供 Cache 将数据写入 DB 的功能

写操作的步骤:

读操作的步骤:

26

异步缓存写入 (Write Back Pattern)

核心思想:只更新缓存,异步更新 DB

异步缓存写入和读写穿透很相似,两者都是由 Cache 服务来负责 Cache 和 DB 的读写。它们俩最大的不同在于:读写穿透是同步更新 Cache 和 DB;而异步缓存写入是异步更新 DB

消息队列中消息的异步写入磁盘、MySQL 的 InnoDB Buffer Pool 机制都用到了这种策略

异步缓存写入下 DB 的写性能非常高,非常适合一些数据经常变化又对数据一致性没有那么高的要求的场景,如:浏览量、点赞量等