概览

缓存是一个有着更快的查询速度的存储技术,这里的更快是指比起从初始的数据源查询(比如数据库,以下都称作数据库)而言。我们经常会把频繁请求的或是耗时计算的数据缓存起来,在程序收到请求这些数据的时候可以直接从缓存中查询数据返回给客户端来提高系统的吞吐量,现在我们来看看有哪些缓存模式可以考虑。

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-ThroughCache-Aside很相似,不同点在于程序不需要再去管理从哪去读数据(缓存还是数据库)。相反它会直接从缓存中读数据,该场景下是缓存去决定从哪查询数据。当我们比较两者的时候这是一个优势因为它会让程序代码变得更简洁。

Write-Through

Write-Through下所有的写操作都经过缓存,每次我们向缓存中写数据的时候,缓存会把数据持久化到对应的数据库中去,且这两个操作都在一个事务中完成。因此,只有两次都写成功了才是最终写成功了。这的确带来了一些写延迟但是它保证了数据一致性。

同时,因为程序只和缓存交互,编码会变得更加简单和整洁,当你需要在多处复用相同逻辑的时候这点变的格外明显。

当使用Write-Through的时候一般都配合使用Read-Through

Write-Through适用情况有:

  • 需要频繁读取相同数据
  • 不能忍受数据丢失(相对Write-Behind而言)和数据不一致

Write-Through的潜在使用例子是银行系统。

Write-Behind

Write-BehindWrite-Through在“程序只和缓存交互且只能通过缓存写数据”这一点上很相似。不同点在于Write-Through会把数据立即写入数据库中,而Write-Behind会在一段时间之后(或是被其他方式触发)把数据一起写入数据库,这个异步写操作是Write-Behind的最大特点。

数据库写操作可以用不同的方式完成,其中一个方式就是收集所有的写操作并在某一时间点(比如数据库负载低的时候)批量写入。另一种方式就是合并几个写操作成为一个小批次操作,接着缓存收集写操作(比如5个)一起批量写入。

异步写操作极大的降低了请求延迟并减轻了数据库的负担。同时也放大了数据不一致的。比如有人此时直接从数据库中查询数据,但是更新的数据还未被写入数据库,此时查询到的数据就不是最新的数据。

总结

真实的系统中需求都不太一样,我们应该根据自己的需要来选择一个或组合几个模式来完成实现。

参考

缓存模式(Cache Aside、Read Through、Write Through、Write Behind)的更多相关文章

  1. 微软BI 之SSIS 系列 - Lookup 组件的使用与它的几种缓存模式 - Full Cache, Partial Cache, NO Cache

    开篇介绍 先简单的演示一下使用 Lookup 组件实现一个简单示例 - 从数据源表 A 中导出数据到目标数据表 B,如果 A 数据在 B 中不存在就插入新数据到B,如果存在就更新B 和 A 表数据保持 ...

  2. Cache-Aside Pattern(缓存模式)

    Load data on demand into a cache from a data store. This pattern can improve performance and also he ...

  3. SQLite剖析之异步IO模式、共享缓存模式和解锁通知

    1.异步I/O模式    通常,当SQLite写一个数据库文件时,会等待,直到写操作完成,然后控制返回到调用程序.相比于CPU操作,写文件系统是非常耗时的,这是一个性能瓶颈.异步I/O后端是SQLit ...

  4. Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式

    android线程池的理解,晚上在家无事 预习了一下android异步加载的例子,也学习到了一个很重要的东东 那就是线程池+缓存  下面看他们的理解.[size=1.8em]Handler+Runna ...

  5. 【转】Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式

    http://www.cnblogs.com/wanqieddy/archive/2013/09/06/3305482.html android线程池的理解,晚上在家无事 预习了一下android异步 ...

  6. KVM几种缓存模式

    原文在这里: http://pic.dhe.ibm.com/infocenter/lnxinfo/v3r0m0/index.jsp?topic=%2Fliaat%2Fliaatbpkvmguestca ...

  7. 【转】[Android实例] Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式

    android线程池的理解,晚上在家无事 预习了一下android异步加载的例子,也学习到了一个很重要的东东 那就是线程池+缓存  下面看他们的理解. [size=1.8em]Handler+Runn ...

  8. django 三种缓存模式的使用及注意点

    Django 缓存模式的使用(主要针对RestFul设计模式的项目) 有三种模式: 全站使用缓存模式(整个项目每个接口都会使用缓存,缺点:所以接口都无法实时性获取数据) 单独视图缓存模式(单个接口使用 ...

  9. [Android实例] Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式

    android线程池的理解,晚上在家无事 预习了一下android异步加载的例子,也学习到了一个很重要的东东 那就是线程池+缓存  下面看他们的理解. [size=1.8em]Handler+Runn ...

随机推荐

  1. buuctf-pwn:jarvisoj_level6_x64

    jarvisoj_level6_x64 只能申请unsorted bin大小下的unlink IDA看一下,可以发现edit里面有任意堆溢出的情况(realloc造成堆溢出) 然后free里面有UAF ...

  2. jdk1.8特性2

    public class User { private Long id; private String userName; private String roleName; private Strin ...

  3. 老板下了死命令,要把日志系统切换到Logback

    Log4j 介绍过了,SLF4J 也介绍过了,那接下来,你懂的,Logback 就要隆重地登场了,毕竟它哥仨有一个爹,那就是巨佬 Ceki Gulcu. 就在昨天,老板听我说完 Logback 有多牛 ...

  4. 编排yml文件剖析

    # yaml格式的pod定义文件完整内容: apiVersion: v1       #必选,版本号,例如v1 kind: Pod       #必选,Pod metadata:       #必选, ...

  5. python进程间共享数值、字典、列表变量

    ##python进程间共享数值.字典.列表变量 关注公众号"轻松学编程"了解更多. import multiprocessing def worker(num, mgr_dict, ...

  6. 基于gin的golang web开发:访问mysql数据库

    web开发基本都离不开访问数据库,在Gin中使用mysql数据库需要依赖mysql的驱动.直接使用驱动提供的API就要写很多样板代码.你可以找到很多扩展包这里介绍的是jmoiron/sqlx.另外还有 ...

  7. print( "Hello,NumPy!" )

    print( "Hello,NumPy!" ) 学习痛苦啊,今天学,明天丢.这种天气,还是睡觉最舒服了. 咱说归说,闹归闹,但还是得学才行啊. 之前在学习的过程中一直都有记录笔记的 ...

  8. vim实现CTRL+S为保存快捷键

    用vim正撸代码撸的飞起,突然Xshell就掉线了,真是太蛋疼了. 于是开始怀念起vs下撸代码时随时随地ctrl+s保存的快捷键,百度了一下,网上的vim实现ctrl+s保存的快捷键设置都有问题,自己 ...

  9. salesforce零基础学习(九十八)Salesforce Connect & External Object

    本篇参考: https://trailhead.salesforce.com/en/content/learn/modules/lightning_connect https://help.sales ...

  10. B/S图书管理系统

    B/S图书管理系统 系统管理 ①新用户注册 ②用户信息修改:修改信息,修改密码 ③锁定用户 ④注销用户 书籍管理 ①新书入库 ②借书办理 ③还书办理 ④书记注销 个人管理 ①图书查询 ②借书单查询 ③ ...