三种经典的缓存使用模式

缓存可以提升性能,缓解数据库压力,但是使用缓存也会导致数据不一致的问题,一般我们是如何使用缓存呢?有三种经典的缓存使用模式:

  • Cache-Aside Pattern
  • Read-Through/Write-through
  • Write-behind

Cache Aside Pattern旁路缓存模式

适用场景:读请求较多,应用最广泛。
旁路缓存模式中服务端需要同时维护DB和Cache,并且是以DB的结果为准。

读请求

1.读的时候,先读缓存,缓存命中的话,直接返回数据
2.缓存没有命中的话,就去读数据库,从数据库取出数据,放入缓存后,同时返回响应。
在这里插入图片描述

写请求:

更新的时候,先更新数据库,然后再删除缓存 。
在这里插入图片描述

自我思考

如果在写数据的过程中,可以先删除cache,再更新DB吗?
答案: 答案肯定是不行的,请求1先把cache中的数据删除 -> 请求2从DB中读取数据 -> 请求1再把DB中的数据更新(解决方法:缓存延时双删)
在写数据的过程中,如果先写DB,再删除cache就不会造成数据不一致了吗?
理论上来说还是会出现数据不一致的问题,不过概率很小,因为缓存的写入速度是比数据库写入速度快很多。
这个过程可以简单的描述为: 1.B-read redis miss 2.B-read db 3.A-write db 4.A-del redis 5.B-write redis(条件需要发生在读缓存时缓存失效,而且并发着有一个写操作。而实际上数据库的写操作会比读操作慢得多,缓存的写入速度是比数据库写入速度快很多。而且还要锁表,而读操作必须在写操作前进入数据库操作,而又要晚于写操作更新缓存,所有的这些条件都具备的概率其实并不大。)

Cache Aside Pattern 的缺陷。
缺陷1:首次请求数据一定不在 cache 的问题
解决办法:可以将热点数据可以提前放入cache 中。
缺陷2:写操作比较频繁的话导致cache中的数据会被频繁被删除,这样会影响缓存命中率 。
解决办法:

  • 数据库和缓存数据强一致场景 :更新DB的时候同样更新cache,不过我们需要加一个锁/分布式锁来保证更新cache的时候不存在线程安全问题。
  • 可以短暂地允许数据库和缓存数据不一致的场景 :更新DB的时候同样更新cache,但是给缓存加一个比较短的过期时间,这样的话就可以保证即使数据不一致的话影响也比较小。

Read-Through/Write-Through(读写穿透)

适用场景:服务端把Cache视为主要数据源,Cache服务分担请求线程的工作、执行DB的读写,提高并发。
读写穿透中服务端把cache视为主要数据存储,从中读取数据并将数据写入其中。cache服务负责将此数据读取和写入DB,从而减轻应用程序的职责。

写:

先查cache,cache中不存在,直接更新DB。
cache中存在,则先更新cache,然后cache服务自己更新DB(同时更新DB和cache)。
写操作步骤:同步更新Cache和DB。相当于请求线程只需更新Cache,或DB,剩下的操作由Cache服务完成。
在这里插入图片描述

读:

读操作步骤:和旁路缓存模式的读操作类似,只是从缓存中读不到时,由Cache服务自己将从DB读到的数据写入缓存。
先从cache中读取数据,读取到直接返回。
从cache中读取不到,则先从DB加载写入到cache后返回响应。
如下图:
在这里插入图片描述

读写穿透实际是在旁路缓存之上进行了封装。在旁路缓存下,发生读请求的时候,如果cache中不存在对应的数据,是由客户端自己负责把数据写入cache,而读写穿透则是cache服务自己来写入缓存,这对客户端是透明的。
和旁路缓存一样,读写穿透也存在首次请求数据一定不在cache中的问题,对于热点数据可以提前写入缓存中。

异步缓存写入(Write Behind Pattern)

适用场景:写请求较多,对一致性要求较低
写操作步骤:和读写穿透模式的写操作类似,只是会只更新缓存,再异步更新DB。
读操作步骤:和读写穿透模式的读操作类似。
异步缓存写入和读写穿透很相似,两者都是由cache服务来负责cache和DB的读写。
两者最大的不同点就是:读写穿透是同步更新DB和cache,而异步缓存写入则是只更新cache,不直接更新DB,而是改为异步批量的方式更新DB。
很明显,这种方式对数据一致性带来了更大的挑战,比如cache数据可能还没异步更新DB,cache服务可能就挂了。
这种策略在我们平时开发过程中也非常少见,但是不代表它的应用场景少,比如消息队列中消息的异步写入磁盘、MySQL的InnoDB Buffer Pool机制都用到了这种策略。
异步缓存写入的写性能非常高,非常适合写数据经常变化又对数据一致性要求没那么高的场景下使用,比如浏览量、点赞量场景,MySQL的InnoDB Buffer Pool机制 就使用到这种模式等。

操作缓存的时候,删除缓存呢,还是更新缓存?
更新缓存相对于删除缓存,还有两点劣势:
如果你写入的缓存值,是经过复杂计算才得到的话。更新缓存频率高的话,就浪费性能啦。
在写数据库场景多,读数据场景少的情况下,数据很多时候还没被读取到,又被更新了,这也浪费了性能呢(实际上,写多的场景,用缓存也不是很划算了)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值