Cache-Aside

该模式是从数据仓库中将数据加载到缓存中,从而提高访问速度的一种模式。该模式可以有效的提高性能,同时也能一定程度上保证缓存中的数据和数据仓库中的数据的一致性,和同步数据到数据仓库中。

问题

应用通过缓存来优化针对数据仓库的重复访问。当然,令缓存中的数据永远和数据仓库中数据保持一致是不切实际的。应用中的缓存应该事先一些策略来辅助更新缓存保证数据的一致,当然,也需要检测数据过期等情况来进行一定的处理。

解决方案

很多商业化的缓存系统都提供read-through和write-through/write-behind的操作。在这些系统中应用从缓存的引用中获得数据。如果数据不再缓存中,请求将透过缓存到数据仓库来获取数据,然后将数据写入到缓存中。任何对缓存中的数据的修改,在之后也会写会到数据仓库之中。

对于那些不提供这个功能的缓存系统,就轮到应用来自己将数据保持在缓存之中了。

应用可以通过实现Cache-Aside策略来实现read-through的功能。这个策略会根据需要来从数据仓库获取数据。下图则是Cache-Aside模式的基本运行方式:

  1. 判断读取的项目是否在缓存中
  2. 如果项目不再缓存中,从数据仓库中将数据读出来
  3. 将新的项目写入缓存

如果应用不是读取信息而是更新信息,它可以模仿write-through的策略:

  1. 将信息的更新同步到数据仓库
  2. 令缓存中关联的过期数据失效

当这个数据在下一次需要的时候,使用Cache-Aside模式将会在获取数据的时候,同时从数据仓库中获取数据,并且写到Cache之中。

需要考虑的问题

当在实现如下模式的时候,需要考虑一些问题:

  1. 缓存数据的生存时间:很多Cache实现了过期的策略的,这些过期的策略可以实现数据的更新,将旧数据失效化,同事也令一定时间没有访问的数据失效。为了让Cache-Aside模式能够生效,开发者必须确保过期策略能够正确匹配应用所访问的数据。同时注意不能让过期时间太短,因为太短的过期时间会令应用频繁的从数据仓库中来获取数据来添加到Cache之中。当然,也不要配置超时的时间太长,过长的超时时间会让缓存的数据荣誉。Cache的性能是跟其相关的数据的读取周期等信息高度相关的。
  2. 去除数据:绝大多数的缓存跟数据仓库比起来,容量是很有限的,所以,如果可以的话,Cache会移除数据。多数的Cache会采用LRU的策略来移除缓存中的数据,当然,移除的策略也是可以自定义的。配置全局的过期属性和缓存的其他属性,可以确保Cache消耗的内存资源是搞笑的。当然,通常不会只配置一个全局的过期策略,。举例来说,不同的缓存从数据仓库中获取资源很昂贵的时候而经常访问的话。
  3. 准备Cache:很多的解决方案会多数情况在应用启动的过程中,就将数据仓库中的数据写入到缓存之中。Cache-Aside模式就算在一些数据过期或者移除的情况下仍然很多时候是很有用的。
  4. 一致性:实现Cache-Aside模式并不能保证Cache和数据仓库之间的数据一致性。因为数据仓库中的数据可能在任何的时候都可能由其他程序锁修改,而这个修改不会及时的反映到Cache上,只有在下一次Cache从数据仓库中更新数据的时候才会有解决这个数据不一致的问题。如果数据仓库中数据频繁由非Cahce程序更新的话,这种问题同步问题hi变得更加明显。
  5. 本地(内存)缓存:Cache也是可以做到应用本身里面的。Cache-Aside模式在一些应用频繁访问相同的数据的时候尤其有效。然而,本地Cache都是应用私有的,是属于每个应用中独有的额外的拷贝。所以这个数据可能很快在不同的应用中就不一致了,所以刷新的频率最好更快来保证一致。在有些情况下可以使用共享的缓存,有的时候也可以使用本地Cache,具体使用哪一种就需要根据实际的场景来判断。

什么时候使用Cache-Aside模式

什么时候使用:

  • 当Cache不提供原生的Read-Through和Write-Through操作的时候
  • 资源的需求是不可预测的时候。Cache-Aside模式令应用可以根据需求来加载数据。对于应用需求什么数据,不需要提前做出假设。

代码举例

在Windows Azure中开发者可以使用Windows Azure Cache来创建一个分布式的由多个应用实例共享的缓存。下面代码中的GetMyEntityAsync方法的实现就是一个基于Windows Azure Cache的Cache-Aside模式的实现。这个方法通过Read-Through的方式从缓存中获取数据。

一个对象通过一个整数ID作为Key来限定。GetMyEntityAsync方法根据这个key生成了一个字符串Key(Windows Azure Cache API是通过字符串来作为Key值的),然后尝试通过这个缓存来获取对应的对象。如果找到了匹配条目,那么就直接返回匹配条目,如果缓存中没有匹配条目,GetMyEntityAsync方法会从数据仓库中获取对象,然后将这个对象添加到缓存之中,然后再返回这个对象(下面代码从数据仓库中获取代码的部分是省略了的,因为整个模式跟数据仓库的访问是独立的)。需要注意的是,缓存的条目是配置按过期顺序的,防止缓存长期不更新也不被使用造成资源浪费。

private DataCache cache;
...
public async Task<MyEntity> GetMyEntityAsync(int id)
{
// Define a unique key for this method and its parameters.
var key = string.Format("StoreWithCache_GetAsync_{0}", id);
var expiration = TimeSpan.FromMinutes(3);
bool cacheException = false;
try
{
// Try to get the entity from the cache.
var cacheItem = cache.GetCacheItem(key);
if (cacheItem != null)
{
return cacheItem.Value as MyEntity;
}
}
catch (DataCacheException)
{
// If there is a cache related issue, raise an exception
// and avoid using the cache for the rest of the call.
cacheException = true;
}
// If there is a cache miss, get the entity from the original store and cache it.
// Code has been omitted because it is data store dependent.
var entity = ...;
if (!cacheException)
{
try
{
// Avoid caching a null value.
if (entity != null)
{
// Put the item in the cache with a custom expiration time that
// depends on how critical it might be to have stale data.
cache.Put(key, entity, timeout: expiration);
}
}
catch (DataCacheException)
{
// If there is a cache related issue, ignore it
// and just return the entity.
}
}
return entity;
}

上面的例子使用了 Windows Azure Cache的API来访问数据仓库和从Cache中获取数据。想了解更多关于Windows Azure Cache API的信息,可以参考MSDN上面的使用Windows Azure 缓存

下面展示的UpdateEntityAsync方法展示了如何令应用修改缓存的数据失效的。这也是Write-Through方法的一个举例。其中的代码会更新数据仓库,然后通过调用Remove方法来移除数据仓库中的数据。

注意:在下面的一些操作的顺序是十分重要的。如果缓存先被移除了,然后缓存才更新的话,客户端在获取数据的时候会有一定的概率

直接从数据仓库里面获取还没有更新的过期数据。

//C#
public async Task UpdateEntityAsync(MyEntity entity)
{
// Update the object in the original data store
await this.store.UpdateEntityAsync(entity).ConfigureAwait(false); // Get the correct key for the cached object.
var key = this.GetAsyncCacheKey(entity.Id); // Then, invalidate the current cache object
this.cache.Remove(key);
} private string GetAsyncCacheKey(int objectId)
{
return string.Format("StoreWithCache_GetAsync_{0}", objectId);
}

Cache-Aside模式的更多相关文章

  1. 十二:SpringBoot-基于Cache注解模式,管理Redis缓存

    SpringBoot-基于Cache注解模式,管理Redis缓存 1.Cache缓存简介 2.核心API说明 3.SpringBoot整合Cache 3.1 核心依赖 3.2 Cache缓存配置 3. ...

  2. SpringBoot2.0 基础案例(13):基于Cache注解模式,管理Redis缓存

    本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.Cache缓存简介 从Spring3开始定义Cache和Cac ...

  3. 《JavaScript模式》第4章 函数

    @by Ruth92(转载请注明出处) 第4章:函数 一.JavaScript 中函数的两个重要特征 函数是第一类对象,可以作为带有属性和方法的值以及参数进行传递: 函数提供了局部作用域,而其他大括号 ...

  4. Cache的原理、设计及实现

    Cache的原理.设计及实现 前言 虽然CPU主频的提升会带动系统性能的改善,但系统性能的提高不仅仅取决于CPU,还与系统架构.指令结构.信息在各个部件之间的传送速度及存储部件的存取速度等因素有关,特 ...

  5. oracle 11g 之 result cache

    oracle 11g 之 result cache 今天是2013-10-12,打算最近时间研究一下shared pool的相关原理以及awr报告分析.今天学习一下在oracle 11g shared ...

  6. [z]计算机架构中Cache的原理、设计及实现

    前言 虽然CPU主频的提升会带动系统性能的改善,但系统性能的提高不仅仅取决于CPU,还与系统架构.指令结构.信息在各个部件之间的传送速度及存储部件的存取速度等因素有关,特别是与CPU/内存之间的存取速 ...

  7. 记一个bootloader的cache问题

    问题背景 最近往一个armv7板子的bootloader中移植了解压算法,移植本身还比较顺利,但移植完了发现,功能是正常的,但效率大打折扣.解压同样的数据,耗时大约是uboot的10倍. 初步定位 从 ...

  8. Spring Cache Redis结合遇到的坑

    业务上需要把一些数据放到redis里面,但是系统逻辑代码差不多编写完成了,怎么整?用Spring Cache啊,对既有业务逻辑侵袭极小. 于是尝试调查了一下,遇到一些问题分享一下(本文使用Spring ...

  9. 11g新特性-查询缓存(1)

    众所周知,访问内存比访问硬盘快得多,除非硬盘体系发生革命性的改变.可以说缓存在Oracle里面无处不在,结果集缓存(Result Cache)是Oracle Database 11g新引入的功能,引入 ...

  10. GPS部标平台的架构设计(九)-GPS监控客户端设计

    交通部的部标过检,所有的测试都是从客户端发起的,也是在客户端体现的,在客户端承载了部标标准所要求的所有的功能,是整个部标平台当中工作量最大的部分,也是最繁琐的部分. 客户端设计面临两个问题: 1.基于 ...

随机推荐

  1. java重载

    public class overLaod { public static void main(String[] args) { // TODO Auto-generated method stub ...

  2. Java类修饰符的使用与作用以及常见问题

    首先明确,类是放在文件里的,在文件里面的不同位置就有不同的作用,就是不同类型的类. 1, 顶级类or外部类:包括两种,一个文件中与文件名同名称的类我们称作顶级类(也是外部类),如果在一个文件中的一个类 ...

  3. 使用Qt框架开发http服务器问题的记录

    最近需求需要开发一款 HTTP ,然后由于先前接触过Qt,就直接用Qt写HTTP服务器了,也是为了当作练手,要不然是直接上HTTP框架的. 后端用C++ Qt框架 前端为了练手 当然是纯生的 js h ...

  4. jquery Mobile入门—多页面切换示例学习

    1.在JQuery Mobile中,多个页面的切换是通过<a>元素.并将<href>属性设置为#+对应的id号的方式进行的. 2.多页面切换示例代码: 复制代码代码如下: &l ...

  5. docker安装后启动不了 解决方法

    第一种情况: 可能是你的selinux没有disabled,导致了守护docker的deamon进程启动不了 查看系统日志如果发现下列信息: May 7 12:34:14 localhost dock ...

  6. System.Reflection 获取描述

    我们需要获取类,属性,方法的描述.这个跟获取枚举的描述一样,需要我们通过反射来做.这还需要我们的利用System.ComponentModel:Description  的属性来完成. 新建一个类:使 ...

  7. web性能优化之GZIP压缩

    从服务端优化来说,通过对服务端做压缩配置可以大大减小文本文件的体积,从而使加载文本的速度成倍的加快.目前比较通用的压缩方法是启用gzip压缩.它会把浏览器请求的页面,以及页面中引用的静态资源以压缩包的 ...

  8. 【星云测试】开发者测试(2)-采用精准测试工具对J2EE Guns开发框架进行测试

    配置测试Guns Guns简介 Guns是一个近几年来基于SpringBoot的开源便利且较新的JavaEE项目开发框架,它整合了springmvc + shiro + mybatis-plus + ...

  9. ansible批量修改用户密码

    实现批量修改目标主机多个用户密码: --- - hosts: testchanange passwd gather_facts: false tasks: - name: change you pas ...

  10. Java中的监听器

    servlet的技术规范包括三个:servlet,listener,filter,今天记录一下listener的学习. 监听器就是监听某个对象的状态变化的技术.监听器包括事件源,监听器,注册监听器以及 ...