缓存模式(Cache Aside、Read Through、Write Through、Write Behind)
概览
缓存是一个有着更快的查询速度的存储技术,这里的更快是指比起从初始的数据源查询(比如数据库,以下都称作数据库)而言。我们经常会把频繁请求的或是耗时计算的数据缓存起来,在程序收到请求这些数据的时候可以直接从缓存中查询数据返回给客户端来提高系统的吞吐量,现在我们来看看有哪些缓存模式可以考虑。
Cache-Aside
Cache-Aside是最广泛使用的缓存模式之一,如果能正确使用Cache-Aside的话,能极大的提升应用性能,Cache-Aside可用来读或写操作。
读操作
我们先来看下读操作的数据流:
- 1、程序接收数据查询的请求
- 2、程序检查要查询的数据是否在缓存上
- 如果存在(cache hit),从缓存上查询出来
- 如果不存在(cache miss),从数据库中检索数据并存入缓存中
- 3、程序返回要查询的数据

在Spring中,可如下实现,当getRecordForSearch()方法被调用的时候,如果缓存中存在对应key的数据,那就会自动的从缓存中获取(此时方法体不会被执行),当缓存中不存在key对应数据的时候,会执行方法体从数据库中查询数据并设置到缓存中去。
@Cacheable("default", key="#search.keyword)
public Record getRecordForSearch(Search search)
更新操作
如果程序需要更新数据库中的数据且该数据也在缓存上,此时缓存中的数据也需要做相应的处理。为了解决这个不同步的问题来确认数据的一致性和操作性能,有两个方式可按需使用。
缓存失效
该情况下,当请求需要更新数据库数据的时候,缓存中的值需要被删除掉(删除掉就表示旧值不可用了),当下次该key被再次查询到就去数据库中查出最新的数据,在Spring中可实现如下:
@CacheEvict("default", key="#search.keyword)
public Record updateRecordForSearch(Search search)
缓存更新
缓存数据也可以在数据库更新的时候被更新,从而在一次操作中让之后的查询有更快的查询体验和更好的数据一致性,在Spring中可实现如下:
@CachePut("default", key="#search.keyword)
public Record updateRecordForSearch(Search search)
为了应对不用类型的数据需要,有以下缓存加载策略可被选择:
- 使用时加载缓存:当需要使用缓存数据时,就从数据库中把它查询出来,第一次查询之后,接下来的请求都能从缓存中查询到数据。
- 预加载缓存:在项目启动的时候,预加载类似“国家信息、货币信息、用户信息,新闻信息”等不是经常变更的数据。
Read-Through
Read-Through和Cache-Aside很相似,不同点在于程序不需要再去管理从哪去读数据(缓存还是数据库)。相反它会直接从缓存中读数据,该场景下是缓存去决定从哪查询数据。当我们比较两者的时候这是一个优势因为它会让程序代码变得更简洁。

Write-Through
Write-Through下所有的写操作都经过缓存,每次我们向缓存中写数据的时候,缓存会把数据持久化到对应的数据库中去,且这两个操作都在一个事务中完成。因此,只有两次都写成功了才是最终写成功了。这的确带来了一些写延迟但是它保证了数据一致性。
同时,因为程序只和缓存交互,编码会变得更加简单和整洁,当你需要在多处复用相同逻辑的时候这点变的格外明显。

当使用Write-Through的时候一般都配合使用Read-Through。
Write-Through适用情况有:
- 需要频繁读取相同数据
- 不能忍受数据丢失(相对
Write-Behind而言)和数据不一致
Write-Through的潜在使用例子是银行系统。
Write-Behind
Write-Behind和Write-Through在“程序只和缓存交互且只能通过缓存写数据”这一点上很相似。不同点在于Write-Through会把数据立即写入数据库中,而Write-Behind会在一段时间之后(或是被其他方式触发)把数据一起写入数据库,这个异步写操作是Write-Behind的最大特点。
数据库写操作可以用不同的方式完成,其中一个方式就是收集所有的写操作并在某一时间点(比如数据库负载低的时候)批量写入。另一种方式就是合并几个写操作成为一个小批次操作,接着缓存收集写操作(比如5个)一起批量写入。
异步写操作极大的降低了请求延迟并减轻了数据库的负担。同时也放大了数据不一致的。比如有人此时直接从数据库中查询数据,但是更新的数据还未被写入数据库,此时查询到的数据就不是最新的数据。
总结
真实的系统中需求都不太一样,我们应该根据自己的需要来选择一个或组合几个模式来完成实现。
参考
- Cat In Code: Caching Strategies Overview
- Things You Should Know About Database Caching
- Microsoft docs: Cache-Aside pattern
- DZone: The Cache Aside Pattern
- 酷壳:缓存更新的套路
- Cache Consistency with Database
缓存模式(Cache Aside、Read Through、Write Through、Write Behind)的更多相关文章
- 微软BI 之SSIS 系列 - Lookup 组件的使用与它的几种缓存模式 - Full Cache, Partial Cache, NO Cache
开篇介绍 先简单的演示一下使用 Lookup 组件实现一个简单示例 - 从数据源表 A 中导出数据到目标数据表 B,如果 A 数据在 B 中不存在就插入新数据到B,如果存在就更新B 和 A 表数据保持 ...
- Cache-Aside Pattern(缓存模式)
Load data on demand into a cache from a data store. This pattern can improve performance and also he ...
- SQLite剖析之异步IO模式、共享缓存模式和解锁通知
1.异步I/O模式 通常,当SQLite写一个数据库文件时,会等待,直到写操作完成,然后控制返回到调用程序.相比于CPU操作,写文件系统是非常耗时的,这是一个性能瓶颈.异步I/O后端是SQLit ...
- Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式
android线程池的理解,晚上在家无事 预习了一下android异步加载的例子,也学习到了一个很重要的东东 那就是线程池+缓存 下面看他们的理解.[size=1.8em]Handler+Runna ...
- 【转】Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式
http://www.cnblogs.com/wanqieddy/archive/2013/09/06/3305482.html android线程池的理解,晚上在家无事 预习了一下android异步 ...
- KVM几种缓存模式
原文在这里: http://pic.dhe.ibm.com/infocenter/lnxinfo/v3r0m0/index.jsp?topic=%2Fliaat%2Fliaatbpkvmguestca ...
- 【转】[Android实例] Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式
android线程池的理解,晚上在家无事 预习了一下android异步加载的例子,也学习到了一个很重要的东东 那就是线程池+缓存 下面看他们的理解. [size=1.8em]Handler+Runn ...
- django 三种缓存模式的使用及注意点
Django 缓存模式的使用(主要针对RestFul设计模式的项目) 有三种模式: 全站使用缓存模式(整个项目每个接口都会使用缓存,缺点:所以接口都无法实时性获取数据) 单独视图缓存模式(单个接口使用 ...
- [Android实例] Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式
android线程池的理解,晚上在家无事 预习了一下android异步加载的例子,也学习到了一个很重要的东东 那就是线程池+缓存 下面看他们的理解. [size=1.8em]Handler+Runn ...
随机推荐
- java并发与多线程面试题与问题集合
http://www.importnew.com/12773.html https://blog.csdn.net/u011163372/article/details/73995897 ...
- 如何用vue实现一个矩形标记区域 rectangle marker
代码地址:vue-rectangle-marker 一.前言 一些cms系统经常会用到区域标记功能,所以写了个用vue实现的矩形标记区域,包含拖拽.放大缩小.重置功能. 二.实现结果 初始 标记 三. ...
- Servlet学习笔记(二)
目录 Servlet学习笔记(二) Request对象 1.request和response对象: 2.request对象继承体系结构: 3.什么是HttpServletRequest ? 4.Htt ...
- CF1008D Pave the Parallelepiped
容斥原理 解法一: 其他容斥原理的题也可以用这种思想 先把$A$,$B$,$C$分解因数 一种很暴力的想法是,将这些因数分成若干个集合(画出韦恩图),然后对有序数组的三个数分别枚举其位于哪一个集合中 ...
- leetcode99:n-queens
题目描述 N皇后问题是把N个皇后放在一个N×N棋盘上,使皇后之间不会互相攻击. 给出一个整数n,返回n皇后问题的所有摆放方案 例如: 4皇后问题有两种摆放方案 [".Q..", ...
- Shell 筛选符合条件的 ELF 文件
0 运行环境 本机系统:Windows 10 虚拟机软件:Oracle VM VirtualBox 6 虚拟机系统:Ubuntu 18 1 引言 - 编译过程 我们知道在 CPU 上执行的是低级别的机 ...
- 类似阿里双十一的可视化看板是怎么做的?无人机三维GIS看板也来了!
天猫双十一数据可视化看板 每年的双十一,天猫都会在整点时刻直播战绩,惊叹于可怕战绩的同时,也会被背后展示的数据大屏吸引,这样让人眼前一亮的可视化数据看板是怎么做出来的? 所谓可视化数据看板,就是挂在墙 ...
- Activit的心路历程:获取当前节点的下一节点【可能存在多个】的nodeId
上一任务节点 在我的开发任务中,突然给我提出了一个待办任务需要获取当前任务节点下一任务节点的表单信息,刚开始搞得我有点措手不及,后来仔细是靠后,灵感一下,直接操作流程的bpmn信息就可以获取到节点信息 ...
- spring处理静态资源方式
1. <mvc:default-servlet-handler/>default-servlet-handler在SpringMVC上下文定义一个org.springframework.w ...
- 类和对象在JVM中是如何存储的,竟然有一半人回答不上来!
前言 这篇博客主要来说说类与对象在JVM中是如何存储的,由于JVM是个非常庞大的课题,所以我会把他分成很多章节来细细阐述,具体的数量还没有决定,当然这不重要,重点在于是否可以在文章中学到东西,是否对J ...