@@ -12,105 +12,106 @@ tag:
1212
1313但是,搞懂3种常见的缓存读写策略对于实际工作中使用缓存以及面试中被问到缓存都是非常有帮助的!
1414
15- 下面我会简单介绍一下自己对于这 3 种缓存读写策略的理解。
16-
17- 另外,** 这3 种缓存读写策略各有优劣,不存在最佳,需要我们根据具体的业务场景选择更适合的。**
18-
19- * 个人能力有限。如果文章有任何需要补充/完善/修改的地方,欢迎在评论区指出,共同进步!——爱你们的 Guide 哥*
15+ ** 下面介绍到的三种模式各有优劣,不存在最佳模式,根据具体的业务场景选择适合自己的缓存读写模式。**
2016
2117### Cache Aside Pattern(旁路缓存模式)
2218
2319** Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式,比较适合读请求比较多的场景。**
2420
25- Cache Aside Pattern 中服务端需要同时维系 DB 和 cache,并且是以 DB 的结果为准。
21+ Cache Aside Pattern 中服务端需要同时维系 db 和 cache,并且是以 db 的结果为准。
2622
2723下面我们来看一下这个策略模式下的缓存读写步骤。
2824
2925** 写** :
3026
31- - 先更新 DB
27+ - 先更新 db
3228- 然后直接删除 cache 。
3329
3430简单画了一张图帮助大家理解写的步骤。
3531
36- ![ ] ( https://img -blog.csdnimg.cn/img_convert/5687fe759a1dac9ed9554d27e3a23b6d .png )
32+ ![ ] ( https://guide -blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/cache-aside-write .png )
3733
3834** 读** :
3935
4036- 从 cache 中读取数据,读取到就直接返回
41- - cache中读取不到的话 ,就从 DB 中读取数据返回
37+ - cache 中读取不到的话 ,就从 db 中读取数据返回
4238- 再把数据放到 cache 中。
4339
4440简单画了一张图帮助大家理解读的步骤。
4541
46- ![ ] ( https://img-blog.csdnimg.cn/img_convert/a8c18b5f5b1aed03234bcbbd8c173a87.png )
47-
42+ ![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/cache-aside-read.png )
4843
4944你仅仅了解了上面这些内容的话是远远不够的,我们还要搞懂其中的原理。
5045
51- 比如说面试官很可能会追问:“** 在写数据的过程中,可以先删除 cache ,后更新 DB 么?** ”
46+ 比如说面试官很可能会追问:“** 在写数据的过程中,可以先删除 cache ,后更新 db 么?** ”
47+
48+ ** 答案:** 那肯定是不行的!因为这样可能会造成 ** 数据库(db)和缓存(Cache)数据不一致** 的问题。
49+
50+ 举例:请求 1 先写数据 A,请求 2 随后读数据 A 的话,就很有可能产生数据不一致性的问题。
51+
52+ 这个过程可以简单描述为:
5253
53- ** 答案: ** 那肯定是不行的!因为这样可能会造成 ** 数据库(DB)和缓存(Cache)数据不一致 ** 的问题。为什么呢?比如说请求1 先写数据A,请求2随后读数据A的话就很有可能产生数据不一致性的问题。这个过程可以简单描述为:
54+ > 请求 1 先把 cache 中的 A 数据删除 -> 请求 2 从 db 中读取数据->请求 1 再把 db 中的 A 数据更新
5455
55- > 请求1先把cache中的A数据删除 -> 请求2从DB中读取数据->请求1再把DB中的A数据更新。
56+ 当你这样回答之后,面试官可能会紧接着就追问:“ ** 在写数据的过程中,先更新 db,后删除 cache 就没有问题了么? ** ”
5657
57- 当你这样回答之后,面试官可能会紧接着就追问:“ ** 在写数据的过程中,先更新DB,后删除cache就没有问题了么? ** ”
58+ ** 答案: ** 理论上来说还是可能会出现数据不一致性的问题,不过概率非常小,因为缓存的写入速度是比数据库的写入速度快很多。
5859
59- ** 答案: ** 理论上来说还是可能会出现数据不一致性的问题,不过概率非常小,因为缓存的写入速度是比数据库的写入速度快很多!
60+ 举例:请求 1 先读数据 A,请求 2 随后写数据 A,并且数据 A 在请求 1 请求之前不在缓存中的话,也有可能产生数据不一致性的问题。
6061
61- 比如请求1先读数据 A,请求2随后写数据A,并且数据A不在缓存中的话也有可能产生数据不一致性的问题。 这个过程可以简单描述为:
62+ 这个过程可以简单描述为:
6263
63- > 请求1从DB读数据A->请求2写更新数据 A 到数据库并把删除cache中的A数据->请求1将数据A写入cache。
64+ > 请求 1 从 db 读数据 A-> 请求 2 更新 db 中的数据 A(此时缓存中无数据 A ,故不用执行删除缓存操作 ) -> 请求 1 将数据 A 写入 cache
6465
6566现在我们再来分析一下 ** Cache Aside Pattern 的缺陷** 。
6667
67- ** 缺陷1 :首次请求数据一定不在 cache 的问题**
68+ ** 缺陷 1 :首次请求数据一定不在 cache 的问题**
6869
69- 解决办法:可以将热点数据可以提前放入cache 中。
70+ 解决办法:可以将热点数据可以提前放入 cache 中。
7071
71- ** 缺陷2:写操作比较频繁的话导致cache中的数据会被频繁被删除 ,这样会影响缓存命中率 。**
72+ ** 缺陷 2:写操作比较频繁的话导致 cache 中的数据会被频繁被删除 ,这样会影响缓存命中率 。**
7273
7374解决办法:
7475
75- - 数据库和缓存数据强一致场景 :更新DB的时候同样更新cache ,不过我们需要加一个锁/分布式锁来保证更新cache的时候不存在线程安全问题 。
76- - 可以短暂地允许数据库和缓存数据不一致的场景 :更新DB的时候同样更新cache ,但是给缓存加一个比较短的过期时间,这样的话就可以保证即使数据不一致的话影响也比较小。
76+ - 数据库和缓存数据强一致场景 :更新 db 的时候同样更新 cache ,不过我们需要加一个锁/分布式锁来保证更新 cache 的时候不存在线程安全问题 。
77+ - 可以短暂地允许数据库和缓存数据不一致的场景 :更新 db 的时候同样更新 cache ,但是给缓存加一个比较短的过期时间,这样的话就可以保证即使数据不一致的话影响也比较小。
7778
7879### Read/Write Through Pattern(读写穿透)
7980
80- Read/Write Through Pattern 中服务端把 cache 视为主要数据存储,从中读取数据并将数据写入其中。cache 服务负责将此数据读取和写入 DB ,从而减轻了应用程序的职责。
81+ Read/Write Through Pattern 中服务端把 cache 视为主要数据存储,从中读取数据并将数据写入其中。cache 服务负责将此数据读取和写入 db ,从而减轻了应用程序的职责。
8182
82- 这种缓存读写策略小伙伴们应该也发现了在平时在开发过程中非常少见。抛去性能方面的影响,大概率是因为我们经常使用的分布式缓存 Redis 并没有提供 cache 将数据写入DB的功能 。
83+ 这种缓存读写策略小伙伴们应该也发现了在平时在开发过程中非常少见。抛去性能方面的影响,大概率是因为我们经常使用的分布式缓存 Redis 并没有提供 cache 将数据写入 db 的功能 。
8384
8485** 写(Write Through):**
8586
86- - 先查 cache,cache 中不存在,直接更新 DB 。
87- - cache 中存在,则先更新 cache,然后 cache 服务自己更新 DB (** 同步更新 cache 和 DB ** )。
87+ - 先查 cache,cache 中不存在,直接更新 db 。
88+ - cache 中存在,则先更新 cache,然后 cache 服务自己更新 db (** 同步更新 cache 和 db ** )。
8889
8990简单画了一张图帮助大家理解写的步骤。
9091
91- ![ ] ( https://img -blog.csdnimg.cn/20210201100340808 .png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MzM3Mjcy,size_16,color_FFFFFF,t_70 )
92+ ![ ] ( https://guide -blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/write-through .png )
9293
93- ** 读(Read Through):**
94+ ** 读(Read Through):**
9495
9596- 从 cache 中读取数据,读取到就直接返回 。
96- - 读取不到的话,先从 DB 加载,写入到 cache 后返回响应。
97+ - 读取不到的话,先从 db 加载,写入到 cache 后返回响应。
9798
9899简单画了一张图帮助大家理解读的步骤。
99100
100- ![ ] ( https://img -blog.csdnimg.cn/img_convert/9ada757c78614934aca11306f334638d .png )
101+ ![ ] ( https://guide -blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/read-through .png )
101102
102- Read-Through Pattern 实际只是在 Cache-Aside Pattern 之上进行了封装。在 Cache-Aside Pattern 下,发生读请求的时候,如果 cache 中不存在对应的数据,是由客户端自己负责把数据写入 cache,而 Read- Through Pattern 则是 cache 服务自己来写入缓存的,这对客户端是透明的。
103+ Read-Through Pattern 实际只是在 Cache-Aside Pattern 之上进行了封装。在 Cache-Aside Pattern 下,发生读请求的时候,如果 cache 中不存在对应的数据,是由客户端自己负责把数据写入 cache,而 Read Through Pattern 则是 cache 服务自己来写入缓存的,这对客户端是透明的。
103104
104105和 Cache Aside Pattern 一样, Read-Through Pattern 也有首次请求数据一定不再 cache 的问题,对于热点数据可以提前放入缓存中。
105106
106107### Write Behind Pattern(异步缓存写入)
107108
108- Write Behind Pattern 和 Read/Write Through Pattern 很相似,两者都是由 cache 服务来负责 cache 和 DB 的读写。
109+ Write Behind Pattern 和 Read/Write Through Pattern 很相似,两者都是由 cache 服务来负责 cache 和 db 的读写。
109110
110- 但是,两个又有很大的不同:** Read/Write Through 是同步更新 cache 和 DB ,而 Write Behind Caching 则是只更新缓存,不直接更新 DB ,而是改为异步批量的方式来更新 DB 。**
111+ 但是,两个又有很大的不同:** Read/Write Through 是同步更新 cache 和 db ,而 Write Behind 则是只更新缓存,不直接更新 db ,而是改为异步批量的方式来更新 db 。**
111112
112- 很明显,这种方式对数据一致性带来了更大的挑战,比如cache数据可能还没异步更新DB的话,cache服务可能就就挂掉了 。
113+ 很明显,这种方式对数据一致性带来了更大的挑战,比如 cache 数据可能还没异步更新 db 的话,cache 服务可能就就挂掉了 。
113114
114- 这种策略在我们平时开发过程中也非常非常少见,但是不代表它的应用场景少,比如消息队列中消息的异步写入磁盘、MySQL 的 InnoDB Buffer Pool 机制都用到了这种策略。
115+ 这种策略在我们平时开发过程中也非常非常少见,但是不代表它的应用场景少,比如消息队列中消息的异步写入磁盘、MySQL 的 Innodb Buffer Pool 机制都用到了这种策略。
115116
116- Write Behind Pattern 下 DB 的写性能非常高,非常适合一些数据经常变化又对数据一致性要求没那么高的场景,比如浏览量、点赞量。
117+ Write Behind Pattern 下 db 的写性能非常高,非常适合一些数据经常变化又对数据一致性要求没那么高的场景,比如浏览量、点赞量。
0 commit comments