缓存读写策略 Cache Aside Pattern,开发必备

我们在前面讲到了当我们业务面临大量写并发的时候,将数据库开发成分布式存储系统,然后又介绍了NoSql数据库与关系型数据库互相配合,以用来更好的服务与我们的业务发展。但随着并发的持续增加,存储数据量的增多,数据库的磁盘 IO 逐渐成了系统的瓶颈,我们需要一种访问更快的组件来降低请求响应时间,提升整体系统性能,这时我们就会使用到缓存。

至于缓存这个概念,这里就不去多说了,我相信大家都懂,也知道它的作用是为了让对数据的请求更快的返回。我们今天要说的就是,应该怎么去使用缓存,通过学习如何选择它的读写策略来应用到我们开发中。

大家是不是觉得缓存读写应该很简单啊,我先去读缓存,读到了就返回数据,读不到我就去数据库读,然后再写到缓存中去,没必要专门的讲解啊。其实当我们真正面临缓存读写的时候,是不一定的,是要根据我们业务去调整我们策略的,而且需要考虑各种因素的,不能这么简单粗暴。那接下来,我们就来看看我们开发中会z怎么做缓存的读写策略。

Cache Aside Pattern

Cache Aside 即为旁路缓存方案,被分为读请求和写请求,下面我们来结合案例看看该怎么去使用。

案例引入

现在我们有一个酒店信息表(为了大家更好的理解Cache Aside,这里不引入复杂的房型那些参数),里面有字段hotel_id,价格字段price等,缓存中按照hotel_id为key存储了这个酒店的价格(10001:100),现在的需求是要将hotel_id为10001的价格改为200,该怎么去做呢?

你可能会说,这简单啊,我就先更新数据库,然后更新缓存嘛,就是下面图示这个样子的:

这样做是会造数据库和缓存数据不一致的,假设,现在有个请求 A 过来,将数据库的hotel_id为10001的价格改为200了,如此同时,请求B 也来了将价格改为300,然后再更新缓存中价格为300;这个时候请求 A才来更新价格,将key为10001的价格改为了200。这个时候,缓存中价格是200,而数据库中是300,所以就造成了两者的数据不一致。因为,这个更新数据库和更新缓存是两个独立的操作,又没有采用并发控制,所以他们执行的顺序我们是不能保证的,而且这种情况发生的频率还是很高的。

扫描二维码关注公众号,回复: 9636396 查看本文章

还有个问题就是会造成数据更新丢失的问题,比如,我们在APP中的积分是100,预定了一间酒店,然后又同时还买了啥保险之类的,这个时候,请求A过来查询缓存是100然后加5积分,再还没写缓存之前,请求B也来了查到的缓存也是100,它同样是来加5积分的,这个时候,就是缓存更新之后就是105积分,而实际上我们的意愿是要增加10积分,就是缓存中得110积分才对。

 

那我们该怎么办?

其实解决上面那样的问题也很简单,我们就在更新缓存的时候,不采取更新的方案,采取删除缓存的方案。即我们在读取数据的时候,如果缓存没命中,就去查数据库,然后再回填到缓存中。

那这种解决方案就是我们的Cache Aside Pattern 旁路缓存策略,它是以数据库的数据为基准的,而缓存是按需才加载,一般被分为读策略和写策略。下面我们再来总结下,它的读写策略步骤:

读策略步骤:

  1. 先从缓存中读取数据

  2. 命中缓存,直接返回

  3. 未命中缓存,则去查数据库

  4. 查到数据库的数据再去写缓存

写策略步骤:

  1. 先更新数据库中数据

  2. 再删除缓存记录

其实像Cache Aside这种缓存策略,也是有缺点的即也会出现数据不一致的情况,但是概率极低,是可以接受的。

Cache Aside策略,在我们平时开发中,应用的最为广泛,但是我们也不能不考虑业务特殊情况,不管三七二十一的一直使用这种读写策略。比如,现在我们有这样的一个需求,我们的酒店后台系统录入了一个新的政策,一录完然后就需要立马给用户展示出来,如果采用先更新数据库,再删除缓存的话,我们数据读写分离会存在延时的,就会存在读取不到数据的情况。

那这个时候,我们需要怎么做呢?那我们就需要对于这种特殊的需求进行一下相应的调整,这时,我在更新数据库写入的时候,我同样也写缓存,这样就可以直接查到缓存数据了。所以,我们在应用这种缓存读写策略的时候,也要关注我们自身的业务。

Cache Aside策略有什么缺陷

 

Cache Aside 最大的缺陷就是,当我们写入操作很频繁的时候,缓存中的数据就会被频繁的删除掉,会直接导致缓存命中率下降,但是如果我们业务中又必须要很高的缓存命中率怎么办呢?比如我们公司有个收费接口,每调用一次就得给钱,所以就使用了这种缓存的方案,可以参考下面两种解决方案:

  1. 在更新数据库记录的时候也更新缓存,我们在代码写更新缓存前加上分布式锁,每次运行一个线程更新缓存,防止并发问题,这种做法就是会对写入性能带了一定影响,毕竟加了锁。

  2. 第二种方案,同样也是更新数据库的时候更新缓存,但是这次我们把缓存设置一个过期时间,一般很短,我根据业务需求计算,即使出现了数据不一致的情况,也是会很快就过期了,可以接受,我们现在就是用这种方案来做的。

总结,今天我们学习了使用缓存时,在我们日常开发中应用最多的缓存读写策略Cache Aside 旁路缓存策略,然后结合案例给大家演示我们该如何根据自己业务去正确使用缓存的读写,解决数据不一致的问题。其实只要有缓存的存在就一定会有数据不一致的问题,我们要做的就是怎么去权衡他们二者关系然后给出我们接受的方案。

下一篇预告:聊聊我们缓存中的高可用话题

发布了29 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/csdn681/article/details/103402275
今日推荐