高并发场景下,到底先更新缓存仍是先更新数据库?| 🏆 技术专题第八期征文

本文 github.com/smileArchit… 已收录。
JavaMap是Java知识地图,旨在让开发者学习不迷路!Java学习请认准JavaMap。git

在大型系统中,为了减小数据库压力一般会引入缓存机制,一旦引入缓存又很容易形成缓存和数据库数据不一致,致使用户看到的是旧数据。github

为了减小数据不一致的状况,更新缓存和数据库的机制显得尤其重要,接下来带领你们踩踩坑。数据库

Cache aside

Cache aside也就是旁路缓存,是比较经常使用的缓存策略。缓存

(1)读请求常见流程微信

Cache aside 读请求
Cache aside 读请求

应用首先会判断缓存是否有该数据,缓存命中直接返回数据,缓存未命中即缓存穿透到数据库,从数据库查询数据而后回写到缓存中,最后返回数据给客户端。markdown

(2)写请求常见流程架构

 Cache aside 写请求
Cache aside 写请求

首先更新数据库,而后从缓存中删除该数据。并发

看了写请求的图以后,有些同窗可能要问了:为何要删除缓存,直接更新不就好了?这里涉及到几个坑,咱们一步一步踩下去。ide

Cache aside踩坑

Cache aside策略若是用错就会遇到深坑,下面咱们来逐个踩。oop

踩坑一:先更新数据库,再更新缓存

若是同时有两个写请求须要更新数据,每一个写请求都先更新数据库再更新缓存,在并发场景可能会出现数据不一致的状况。

先更新数据库,再更新缓存
先更新数据库,再更新缓存

如上图的执行过程:

(1)写请求1更新数据库,将 age 字段更新为18;

(2)写请求2更新数据库,将 age 字段更新为20;

(3)写请求2更新缓存,缓存 age 设置为20;

(4)写请求1更新缓存,缓存 age 设置为18;

执行完预期结果是数据库 age 为20,缓存 age 为20,结果缓存 age为18,这就形成了缓存数据不是最新的,出现了脏数据。

踩坑二:先删缓存,再更新数据库

若是写请求的处理流程是先删缓存再更新数据库,在一个读请求和一个写请求并发场景下可能会出现数据不一致状况。

先删缓存,再更新数据库
先删缓存,再更新数据库

如上图的执行过程:

(1)写请求删除缓存数据;

(2)读请求查询缓存未击中(Hit Miss),紧接着查询数据库,将返回的数据回写到缓存中;

(3)写请求更新数据库。

整个流程下来发现数据库中age为20,缓存中age为18,缓存和数据库数据不一致,缓存出现了脏数据。

踩坑三:先更新数据库,再删除缓存

在实际的系统中针对写请求仍是推荐先更新数据库再删除缓存,可是在理论上仍是存在问题,如下面这个例子说明。

先更新数据库,再删除缓存
先更新数据库,再删除缓存

如上图的执行过程:

(1)读请求先查询缓存,缓存未击中,查询数据库返回数据;

(2)写请求更新数据库,删除缓存;

(3)读请求回写缓存;

整个流程操做下来发现数据库age为20缓存age为18,即数据库与缓存不一致,致使应用程序从缓存中读到的数据都为旧数据。

但咱们仔细想一下,上述问题发生的几率其实很是低,由于一般数据库更新操做比内存操做耗时多出几个数量级,上图中最后一步回写缓存(set age 18)速度很是快,一般会在更新数据库以前完成。

若是这种极端场景出现了怎么办?咱们得想一个兜底的办法:缓存数据设置过时时间。一般在系统中是能够容许少许的数据短期不一致的场景出现。

Read through

在 Cache Aside 更新模式中,应用代码须要维护两个数据源头:一个是缓存,一个是数据库。而在 Read-Through 策略下,应用程序无需管理缓存和数据库,只须要将数据库的同步委托给缓存提供程序 Cache Provider 便可。全部数据交互都是经过抽象缓存层完成的。

Read-Through流程
Read-Through流程

如上图,应用程序只须要与Cache Provider交互,不用关心是从缓存取仍是数据库。

在进行大量读取时,Read-Through 能够减小数据源上的负载,也对缓存服务的故障具有必定的弹性。若是缓存服务挂了,则缓存提供程序仍然能够经过直接转到数据源来进行操做。

Read-Through 适用于屡次请求相同数据的场景,这与 Cache-Aside 策略很是类似,可是两者仍是存在一些差异,这里再次强调一下:

  • 在 Cache-Aside 中,应用程序负责从数据源中获取数据并更新到缓存。
  • 在 Read-Through 中,此逻辑一般是由独立的缓存提供程序(Cache Provider)支持。

Write through

Write-Through 策略下,当发生数据更新(Write)时,缓存提供程序 Cache Provider 负责更新底层数据源和缓存。

缓存与数据源保持一致,而且写入时始终经过抽象缓存层到达数据源。

Cache Provider相似一个代理的做用。

Write-Through流程
Write-Through流程

Write behind

Write behind在一些地方也被成为Write back, 简单理解就是:应用程序更新数据时只更新缓存, Cache Provider每隔一段时间将数据刷新到数据库中。说白了就是延迟写入

Write behind流程
Write behind流程

如上图,应用程序更新两个数据,Cache Provider 会当即写入缓存中,可是隔一段时间才会批量写入数据库中。

这种方式有优势也有缺点:

  • 优势是数据写入速度很是快,适用于频繁写的场景。

  • 缺点是缓存和数据库不是强一致性,对一致性要求高的系统慎用。

总结一下

学了这么多,相信你们对缓存更新的策略都已经有了清晰的认识。最后稍稍总结一下。

缓存更新的策略主要分为三种:

  • Cache aside
  • Read/Write through
  • Write behind

Cache aside 一般会先更新数据库,而后再删除缓存,为了兜底一般还会将数据设置缓存时间。

Read/Write through 通常是由一个 Cache Provider 对外提供读写操做,应用程序不用感知操做的是缓存仍是数据库。

Write behind简单理解就是延迟写入,Cache Provider 每隔一段时间会批量输入数据库,优势是应用程序写入速度很是快。

好了,今天先到这里了,你们学会了吗?

-- END --

不要白嫖,点个赞咯,每一张图都是精心画的~

做者简介: ☕读过几年书:华中科技大学硕士毕业;
😂浪过几个大厂:华为、网易、百度……
😘一直坚信技术能改变生活,愿保持初心,加油技术人!

微信搜索公众号【爱笑的架构师】,关注这个对技术和生活有追求的技术人。

最后推荐一个宝藏开源项目,github.com/smileArchit… 
JavaMap是Java知识地图,让开发者学习不迷路!Java学习请认准JavaMap。
JAVA核心知识点整理(283页,超级详细)免费领取。

🏆 技术专题第八期 | 聊聊缓存的妙用和问题

相关文章
相关标签/搜索