Cache-Aside Pattern解析
使用这种模式,可以帮助我们维护Cache中的数据。
使用Cache容易遇到的问题:
使用缓存,主要是为了将一些重复访问的数据存到缓存,开发者希望缓存中的数据和数据源中的保持一致,这就需要程序中有相应的策略:
- 如果缓存中的数据被更新了,能尽可能快的同步到数据源中
- 如果数据源的数据被修改了,缓存的数据被更新或者删除
解决方案
一些商用的Cache会提供读穿透(read-through)和写穿透(write-through/write-behind)模式:
- 读穿透:程序尝试从缓存中读取数据,如果缓存中没有相应的数据,则会继续从数据源中读取并将其加入到缓存中
- 写穿透:如果尝试更新缓存中的数据,则后台的数据源也会被自动的更新
通过实现Cache-Aside Pattern来模拟读穿透:
当程序更新了信息后,模拟写穿透功能:
- 确保更新的数据存入到数据源中
- 将缓存中的数据标记为无效
适合使用Cache-Aside Pattern的场景:
- 缓存没有提供读穿透和写穿透功能
- 按需加载的数据不可预测
可能不适合使用Cache-Aside Pattern的场景:
- 缓存的对象是静态的(在程序启动的时候就在缓存中添加一个静态对象并长期有效)
- Web应用缓存Session状态,在这种情况下,应该避免客户端和服务器的sticky session
如果使用的Cahce没有提供这2种模式,需要我们在代码中实现,例子如下:
通过Azure Cache,我们可以创建分布式的缓存集群,这样一个应用的多个实例都可以访问。
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();
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;
}
UpdateEntityAsync 实现了写穿透模式:
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中的数据删除掉;如果先删除Cache的数据而后更新数据源,会有小概率发生尝试从缓存获取这个数据,因为它已经被删除掉了,而从数据源读出还没有被更新的旧数据并且将这个旧数据存放到了缓存中。
如果想使用Azure Cache的API,可以参考Using Microsoft Azure Cache
Cache-Aside Pattern解析的更多相关文章
- Cache Aside Pattern
Cache Aside Pattern 即旁路缓存是缓存方案的经验实践,这个实践又分读实践,写实践 对于读请求 先读cache,再读db 如果,cache hit,则直接返回数据 如果,cache m ...
- 缓存实践Cache Aside Pattern
Cache Aside Pattern旁路缓存,是对缓存应用的一个总结,包括读数据方案和写数据方案. 读数据方案 先读cache,如果命中则返回 如果miss则读db 将db的数据存入缓存 写数据方案 ...
- Google guava cache源码解析1--构建缓存器(1)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 1.guava cache 当下最常用最简单的本地缓存 线程安全的本地缓存 类似于ConcurrentHas ...
- 第二章 Google guava cache源码解析1--构建缓存器
1.guava cache 当下最常用最简单的本地缓存 线程安全的本地缓存 类似于ConcurrentHashMap(或者说成就是一个ConcurrentHashMap,只是在其上多添加了一些功能) ...
- CSAPP-Lab05 Cache Lab 深入解析
本文首发于我的知乎专栏:https://zhuanlan.zhihu.com/p/484657229 实验概览 Cache Lab 分为两部分,编写一个高速缓存模拟器以及要求优化矩阵转置的核心函数,以 ...
- Guava Cache源码解析
概述: 本次主要是分析cache的源码,基本概念官方简介即可. 基本类图: 在官方的文档说明中,Guava Cache实现了三种加载缓存的方式: LoadingCache在构建缓存的时候,使用buil ...
- Google guava cache源码解析1--构建缓存器(3)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 下面介绍在LocalCache(CacheBuilder, CacheLoader)中调用的一些方法: Ca ...
- Google guava cache源码解析1--构建缓存器(2)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. CacheBuilder-->maximumSize(long size) /** ...
- Spring Cache 源码解析
这个类实现了Spring的缓存拦截器 org.springframework.cache.interceptor.CacheInterceptor @SuppressWarnings("se ...
随机推荐
- 可以ping通,但是不能connect
实测有效的解决方法: 通过minicom串口连接板子: su stop adbd start adbd 如果再不行,就在终端输入 adb kill-server adb start-server 参考 ...
- AOP 学习笔记
代理是一个设计模式,提供了对目标对象另外的访问方式:即通过代理访问目标对象. 好处:可以在目标对象实现的基础上,增强额外的功能操作. Cglib 代理,也叫作 子类代理. JDK的动态代理有一个限制, ...
- mysql-查看全局变量设置
show global variables like '%sql_mode%' 全局变量
- selenium3各种报错解决办法
解决办法全在这个链接里 http://learn-automation.com/use-firefox-selenium-using-geckodriver-selenium-3
- 【CodeForces 672B】Different is Good
题 字符串所有子串要不同.求修改最少多少个字符. 因为只能是26个字母,显然大于26的不可能有答案,其它情况ans+=u[i]-1:u[i]是字母出现的次数. #include<cstdio&g ...
- 源代码管理工具(上)-SVN基本使用
------------------------------------------------------SVN简介和搭建 ------------------------------------- ...
- form 表单用php来跳转页面
action="submit.php" method="post" fomr 表单的提交跳转:method =post/get,get密码和用户的可见性,密码 ...
- [bzoj4408][Fjoi2016]神秘数
Description 一个可重复数字集合$S$的神秘数定义为最小的不能被$S$的子集的和表示的正整数. 例如$S={1,1,1,4,13}$, $1=1$, $2=1+1$, $3=1+1+1$, ...
- springMVC-自定义数据类型转换器
自定义类型转换器 201603005,今天想了一个问题,Spring中的Conventer是如何实现的,因为他没有绑定类中的属性,它怎么知道要将那个String转换?看了几遍的书也没有找到,后来想想, ...
- 【poj3017】 Cut the Sequence
http://poj.org/problem?id=3017 (题目链接) 题意 给出一个数列要求将它分割成许多块,每块的数的和不超过m,要求每块中最大的数之和最小. Solution 这道题真的很不 ...