缓存读写策略
Cache Aside Pattern(旁路缓存模式)
Cache Aside Pattern适合读多写少的场景。Cache Aside Pattern中服务端需要同时维系DB和cache,并且最终的结果以DB为准。
下面是该策略模式下缓存读写步骤。
写:
- 首先更新数据库
- 然后直接删除cache中的数据
下图展示了该模式下的写步骤:
读:
- 从cache中读取数据,如果缓存命中就直接返回
- 如果cache未命中,就从数据库中读取数据并返回
- 将读取的数据放入缓存中
下图展示了该模式下的读步骤:
Cache Aside Pattern的缺陷:
首次请求的数据一定不在cache中
解决方案:将热点数据提前放入cache中
写操作比较频繁的话会造成cache中的数据被频繁删除,这样会影响缓存命中率。
解决方案:
- 数据库和缓存强一致场景:更新数据库的时候同时更新cache(需要加锁/分布式锁来保证更新cache的时候不存在线程安全问题)。
- 可以短暂地允许数据库和缓存数据不一致的场景:更新数据库的时候同时更新cache,但是给缓存加一个比较短的过期时间,这样就可以保证即使数据不一致但影响比较小。
Read/Write Through Pattern(读写穿透)
Read/Write Through Pattern中服务端把cache视为主要的数据存储,从中独缺数据并且将数据写入其中。cache服务则负责将数据读取和写入数据库,从而减少了应用程序的职责。
下面是该策略模式下缓存读写步骤。
写:
- 先查询cache,cache中不存在,直接更新数据库
- cache中存在,则先更新cache,然后cache服务自己更新数据库(同步更新cache和数据库)
下图展示了该模式下的写步骤:
读:
- 从cache中读取数据,如果缓存命中就直接返回
- 如果缓存不命中,先从数据库中加载,写入到cache后返回响应
下图展示了该模式下的读步骤:
Read-Through Pattern实际只是再Cache-Aside Pattern之上进行了封装。在Cache-Aside Pattern下,发生读请求时,如果cache中不存在对应的数据,是由客户端负责把数据写入到cache,而Read-Through Pattern则是cache服务自己来完成缓存的写入,这个步骤对客户端是透明的。
和Cache Aside Pattern一样,Read-Through Pattern也存在首次请求数据一定不在cache中的问题,因此对于热点数据可以提前放入缓存中。
Wirte Behind Pattern(异步缓存写入)
Write Behind Pattern和Read/Write Through Pattern类似,两者都是由cache服务来负责cache和数据库的读写。但是Read/Write Through是同步更新cache和数据库,而Write Behind Pattern则是只更新缓存,数据库的更新方式改为异步批量更新。
这种方式对数据一致性有很大的挑战,比如cache数据可能还没有更新到数据库,cache服务可能就已经死掉了。这种策略在我们平时开发过程中也非常非常少见,但是不代表它的应用场景少,比如消息队列中消息的异步写入磁盘、MySQL 的 InnoDB Buffer Pool 机制都用到了这种策略。Write Behind Pattern 下数据库的写性能非常高,非常适合一些数据经常变化又对数据一致性要求没那么高的场景,比如浏览量、点赞量。