原创 面试/工作必备!3种常用的缓存读写策略!

发布时间:2021-08-02 09:04:03 浏览 1677 来源:猿笔记 作者:JavaGuide

    搞懂3种常见的缓存读写策略对于实际工作中使用缓存以及面试中被问到缓存都是非常有帮助的!下面我会简单介绍一下自己对于这3种缓存读写策略的理解。**这3种缓存读写策略各有优劣,**CacheAsidePattern是我们平时使用比较多的一个缓存读写模式。下面我们来看一下这个策略模式下的缓存读写步骤,因为这样可能会造成**数据库(DB)和缓存(Cache)数据不一致**的问题?请求2随后读数据A的话就很有可能产生数据不一致性的问题,请求1先把cache中的A数据删除->请求2从DB中读取数据->请求1再把DB中的A数据更新!**在写数据的过程中。


    推荐:接近100Kstar的Java学习/面试指南:[JavaGuide](

    看到很多朋友在简历上写了“* *巧用缓存* *”,但当我问到“* *缓存* *常用的三种读写策略”时,我一脸不解。

    但是了解三种常见的缓存读写策略,对于实际工作中使用缓存,以及面试中被问到缓存都是很有帮助的!

    下面我将简单介绍一下我对这三种缓存读写策略的理解。

    另外,* *这三种缓存读写策略各有利弊,没有最好的,需要根据具体业务场景选择更合适的。**

    *个人能力有限。文章如有需要补充/改进/修改的地方,请在评论区指出,共同进步!-爱你的向导兄弟*

    ###CacheAsidePattern(旁路缓存模式)

    **CacheAsidePattern是我们通常使用较多的一种缓存读写模式,更适合读取请求较多的场景。**

    CacheAsidePattern中服务端需要同时维系DB和cache,并且是以DB的结果为准。

    让我们来看看在这种策略模式下的缓存读写步骤。

    **写**:

    -先更新DB

    -然后直接删除cache。

    画一个简单的图,帮助你理解写作的步骤。

    **读**:

    -从缓存中读取数据,并在读取后直接返回。

    -如果无法从缓存中读取,请从数据库中读取数据并返回

    -再把数据放到cache中。

    画一个简单的图,帮助你理解阅读步骤。

    你理解以上内容是不够的。我们需要理解这些原则。

    比如面试官很可能会问:“* *写数据的过程中可以先删除缓存再更新DB吗?**"

    * *回答:*那肯定不行!因为这可能会导致* *数据库和缓存数据不一致* *。为什么?例如,如果请求1首先写入数据A,然后请求2读取数据A,很可能会出现数据不一致的情况。这个过程可以简单地描述为:

    请求1首先从缓存中删除A数据->请求2从数据库中读取数据->请求1再次更新数据库中的A数据。

    回答完这个问题,面试官可能会马上问:“* *在写数据的过程中,先更新DB再删除缓存没问题?**"

    * *回答:*理论上,数据不一致还是有可能发生的,但是概率很小,因为缓存的写入速度比数据库快得多!

    例如,如果请求1首先读取数据A,请求2稍后写入数据A,并且数据A不在缓存中,也可能出现数据不一致。这个过程可以简单地描述为:

    请求1从DB A读取数据->请求2将更新数据A写入数据库并从缓存中删除数据A->请求1将数据A写入缓存。

    现在我们再来分析一下**CacheAsidePattern的缺陷**。

    * *缺陷1:第一次请求的数据必须不在缓存中的问题* *

    解决方案:热数据可以提前放入缓存。

    * *缺陷2:如果写操作频繁,缓存中的数据会被频繁删除,影响缓存命中率。**

    解决方法:

    -数据库和缓存数据的强一致性:更新DB的时候缓存也是更新的,但是我们需要增加一个锁/分布式锁,以保证更新缓存的时候没有线程安全问题。

    -可以暂时允许数据库和缓存之间的数据不一致:更新DB时,缓存也会更新,但会给缓存增加更短的到期时间,这样即使数据不一致,影响也很小。

    ###Read/WriteThroughPattern(读写穿透)

    在读/写模式中,服务器将缓存作为主要的数据存储,从缓存中读取数据并向其中写入数据。缓存服务负责将这些数据读写到数据库中,从而减轻了应用程序的责任。

    这种缓存读写策略,平时在开发过程中也应该会被朋友发现是非常少见的。大概率是我们经常使用的分布式缓存Redis没有提供cache将数据写入DB的功能。

    **写(WriteThrough):**

    -先查cache,cache中不存在,直接更新DB。

    -cache中存在,则先更新cache,然后cache服务自己更新DB(**同步更新cache和DB**)。

    画一个简单的图,帮助你理解写作的步骤。

    **读(ReadThrough):**

    -从缓存中读取数据,并在读取后直接返回。

    -如果不能读取,先从DB加载,写入缓存,返回响应。

    画一个简单的图,帮助你理解阅读步骤。

    Read-ThroughPattern实际只是在Cache-AsidePattern之上进行了封装。在Cache-AsidePattern下,发生读请求的时候,如果cache中不存在对应的数据,是由客户端自己负责把数据写入cache,而ReadThroughPattern则是cache服务自己来写入缓存的,这对客户端是透明的。

    和CacheAsidePattern一样,Read-ThroughPattern也有首次请求数据一定不再cache的问题,对于热点数据可以提前放入缓存中。

    ###WriteBehindPattern(异步缓存写入)

    WriteBehindPattern和Read/WriteThroughPattern很相似,两者都是由cache服务来负责cache和DB的读写。

    但是,两个又有很大的不同:**Read/WriteThrough是同步更新cache和DB,而WriteBehindCaching则是只更新缓存,不直接更新DB,而是改为异步批量的方式来更新DB。**

    显然,这种方法给数据一致性带来了更大的挑战。例如,如果缓存数据不能异步更新数据库,缓存服务可能会挂起。

    这种策略在我们平时的开发过程中非常非常少见,但并不意味着应用场景很少。例如,将消息队列中的消息异步写入磁盘和MySQL的InnoDBBufferPool机制都使用这种策略。

作者信息

JavaGuide [等级:3] DEV
发布了 127 篇专栏 · 获得点赞 15507 · 获得阅读 1018509

相关推荐 更多