缓存更新策略(Cache Aside Pattern)

一、序言

本文介绍一种缓存更新策略(即 Cache Aside Pattern)。

二、什么是缓存

缓存(Cache)是一种数据存储技术,用于临时存储频繁访问的数据,以便快速访问。缓存通常位于数据请求的前端,可以是内存、磁盘或其他存储介质。其主要目的是提高数据访问的速度和效率,减少对后端数据源(如数据库、网络服务等)的访问次数,从而提升系统的性能和响应速度。
缓存可以应用于各种不同的场景和系统中,包括网络服务器、数据库查询、Web应用程序、操作系统等。常见的缓存技术包括内存缓存、分布式缓存、页面缓存、数据库缓存等。通过合理地使用缓存,可以显著提升系统的性能、可伸缩性和用户体验。

三、缓存更新策略

当数据库中的数据发生变化时,如果缓存中的数据没有同步更新,那么用户可能会读取到过期或者错误的数据,这就导致了数据的不一致。因此,我们需要一种机制来保证当数据库中的数据发生变化时,缓存中的数据能够及时地进行更新。缓存更新策略就是为了保证缓存和数据库之间的数据一致性。
以下是常见的缓存更新策略:

  1. Cache Aside Pattern(旁路缓存模式):缓存的调用者在更新数据库的同时更新缓存,以此来保证缓存与数据库的一致性。
  2. Read/Write Through Pattern(读写穿透模式):在缓存与数据库之间加入一个中间层,缓存的调用者不直接操作缓存和数据库,而是只操作中间层,缓存和数据库的一致性由中间层维护。
  3. Write Behind Caching Pattern(异步缓存写入模式):缓存的调用者只操作缓存,使用异步操作来保证缓存和数据库的一致性。

四、Cache Aside Pattern

Cache Aside Pattern(旁路缓存模式)的核心是由缓存的调用者在更新数据库的同时更新缓存。这种模式有两种实现方案:

  1. 数据库更新,同时缓存更新
  2. 数据库更新,同时缓存失效

五、旁路缓存模式实现方案

针对 Cache Aside Pattern(旁路缓存模式)通常有以下两种实现方案:

  1. 数据库更新,同时缓存更新:数据库更新,同时缓存更新虽然能够保证缓存的一致性,但是却带了一个问题。如果数据频繁更新,将会出现大量的无效写操作(影响性能)。例如:数据库中有一个字段 A = 1 修改了三次,分别是 A = 2,A = 3,A = 4。那么,缓存也将被修改 3 次,若在数据修改期间并没有任何的查询操作,缓存的这三次修改操作只有最后一次有效,前面两次的修改都是无效的。
  2. 数据库更新,同时缓存失效(一般是删除缓存):数据库更新,同时缓存更新会导致大量的无效写操作。为了解决这一问题,我们修改数据库的同时使缓存失效(通常是将缓存直接删掉)而不修改缓存。但是,这时有一个新的问题:缓存无效了,那么下次查询的时候就用不了缓存。这时的处理方式是:在下次查询的时候发现缓存无效,便查询数据库,并重新写入缓存。之后,只要不遇到更新操作(即只有查询操作),接下来就可以一直使用缓存。

综上我们可以发现:数据库更新同时缓存更新这种方案适合一致性要求比较高的场景,而数据库更新同时缓存失效能够兼顾大多数场景的一致性与高性能,所以通常我们会采用数据库更新同时缓存失效的方案来实现 Cache Aside Pattern(旁路缓存模式)。 接下来我们都是以数据库更新同时缓存失效为基础进行讨论

六、数据库与缓存的操作顺序

现在,我们既需要操作数据库又需要操作缓存,操作数据库与缓存的顺序是否有影响呢?

6.1 先删缓存后更新数据库

在这里插入图片描述

先删缓存后更新数据库,若出现上图中的情况将会导致缓存中存入的是旧数据,缓存与数据库出现不一致。而针对这种不一致的情况可以采用下面的方式(延时双删策略)解决:
在这里插入图片描述

延时双删策略之所以要延时一段时间,就是要尽可能保证删除缓存晚于写入缓存,这个时间一般是由实际测试效果得出来的,并非一个固定值。

6.2 先更新数据库后删缓存

在这里插入图片描述

先更新数据库后删除缓存,若出现上图的情况仍会导致缓存与数据库不一致。而针对这种不一致的情况,我们一般不会采取额外的措施,这是为什么呢?
在回答这个问题之前,我们需要有两个基本认知:

  1. 数据库的操作耗时远大于缓存的操作耗时。
  2. 上述两种方案都不能做到 100% 保证缓存与数据库的一致性

基于第一个认知,在查询缓存和写入缓存中间出现更新数据库和删除缓存的情况属于小概率事件。这种小概率事件我们认为基本上不会发生(生产实践中亦是如此)。即使,最后产生了缓存与数据库不一致我们也可以通过一些策略(例如:告警通知),在发生问题时由人工及时介入解决。 基于第二个认知,既然 100% 的一致性两种方案都无法保证,那么在一致性保证差不多的情况下,先更新数据库后删除缓存显然比先删除缓存后更新数据库 + 延时双删策略性能更高(因为延时双删会多一步删除操作)。所以,先更新数据库后删除缓存这种方式在实际的生产实践中使用得较多(注意:只是使用较多,并非只采用这种方式)。限于篇幅,我们接下来只讨论先更新数据库后删缓存的方式。

七、缓存工作流程

7.1 查询请求流程

在这里插入图片描述

当执行查询请求时,缓存的执行流程是:

  1. 当发起查询请求时,请求会先查询缓存
  2. 若查询到缓存,直接返回数据
  3. 若缓存查询失败,便会去数据库查询数据
  4. 将数据库中的数据写入缓存,最后返回数据

7.2 数据修改流程

在这里插入图片描述

当执行修改请求时,缓存的执行流程是:

  1. 修改请求,首先修改数据库
  2. 使缓存失效,一般是直接删除缓存
  3. 返回修改结果

八、FAQ

8.1 数据库与缓存不一致的真正原因是什么

其实,我们仔细思考将会发现:导致数据库与缓存不一致的真正原因是删除缓存先于写入缓存。 写入缓存之前必定有查询数据库的操作,而查询数据库可能会查询到旧数据(即在其他线程更新数据库之前进行了查询),若把写入缓存放在了后面就有可能导致旧数据放入了缓存中,从而导致了缓存不一致。
那么,写入缓存先于删除缓存会有不一致的问题吗?
其实是没有的。即便你之前写入了旧数据,因为后面会执行删除缓存,所以缓存失效了,其他的线程查询缓存失败,就会重新查询数据库获取最新值。

8.2 缓存一致性得不到 100% 的保障为什么我们还会使用

缓存一致性不能做到 100% 是因为多线程环境中的并发问题,倘若我们在单线程的环境中使用,那么就不会存在上述的问题。即使在多线程的环境中,如果并发量并不是特别大一般缓存与数据库的一致性的也能得到保障,即使出现了个别数据的一致性问题,做好告警通知,进行人工处理进行兜底也是可以解决的。所以,最终在高性能和一致性的取舍下我们选择了这种方式来处理缓存。

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值