[Asp.net 5] Caching-缓存架构与源码分析
首先奉献caching的开源地址[微软源码]
1.工程架构

为了提高程序效率,我们经常将一些不频繁修改,但是使用了还很大的数据进行缓存。尤其是互联网产品,缓存可以说是提升效率优化第一利器。微软为我们实现了俩种缓存方式:内存缓存、分布式缓存。个人理解如果缓存在前端电脑内存的缓存叫做内存缓存,如果缓存在其它设备上,那么叫做分布式缓存。
- 俩种缓存方式的优缺点
我开发程序经历过三个时间点,开始的时候从来不使用缓存,之后将数据缓存在内存中,最后使用分布式缓存。内存缓存的优点是速度快,缺点是内存损耗比较大,可能缓存的数据太大的时候就放不下了,另外一个缺点就是对于多前端程序的原则上是不支持的。而分布式缓存的优点是,理论上缓存大小没有上线,可以通过扩充物理硬件进行扩展,对于多前端支持的较好。
Microsoft.Framework.Caching.Abstractions
这个工程定义的是缓存的整体架构。我们的思想是面向接口编程,而不是面向实现编程。所以该工程定义了我们想要的接口

从上图显而易见,微软将内存缓存和分布式缓存割裂开来,而不是我们一般意义上定义一个ICache接口,之后让IMemoryCache和IDistributedCache分别继承ICache接口。
所以我们用分布式缓存,内存缓存原则不能无缝的直接切换。需要我们修改程序代码,或者进行适配封装。
- 分布式缓存
这部分包含内容只包含简单的俩点:配置项(DistributedCacheEntryOptions)、缓存接口(IDistributedCache)。而DistributedCacheEntryExtentions是DistributedCacheEntryOptions的扩展方法包装类,CaceheExtensions是IDistributedCache扩展方法包装类,CacheItemPriority是优先级枚举。
- 内存缓存
内存缓存,微软的设计就比较复杂,考虑到方方面面。首先时缓存的配置项(IMemoryCacheEntryOptions)、缓存接口(IMemoryCache)以及它们扩展项(MemoryCacheEntryExtentions、CacheExtentions)。
但是微软的想法,缓存不止应该只有过期失效,当我程序update一个字段后,我想通知内存缓存,我更改了,那又该怎么办呢?于是微软设计了右上角的部分(*由于代码的持续更新原因右上角部分的接口已经被去掉,由IList<IChangeToken> ExpirationTokens { get; }属性替代,但是原则都是一样的,即外部通知内部,数据已经更新)。
既然外部数据更新能通知缓存,那反向呢?缓存更新是否能够通知外部使用对象呢?答案是这个可以支持,所有上边框,下面的部分。
既然能外部修改通知内部,内部修改也能通知外部应用程序。设计已经趋近完美了?微软说还不够,于是上图左边的部分产生了。它的意义就是,我可以为缓存创建一个范围,至于范围是做什么的?答案是“我也不知道”,但是从内存缓存的实现上来看,是用于整体缓存token等信息的。
缓存配置项的时间选项:AbsoluteExpiration、AbsoluteExpirationRelativeToNow、SlidingExpiration。分别表示的是绝对的过期时间点、相对于现在多久的绝对过期时间点,有效期时长。我们注意下类型AbsoluteExpiration是DateTimeOffset不是DateTime。(*DateTimeOffset 是对于1970年1月1日0时的时间偏移量,和DateTime相比,缺少时区的概念。而此处不需要有时区相关概念,所以选用了DateTimeOffset )。
Microsoft.Extensions.Caching.Memory
内存缓存的实现。此处代码结构如下图所示:

- 大逻辑
1,缓存太大时,压缩缓存空间(个人理解)
系统创建内存缓存对象(MemoryCache)的时候,同时创建GcNotification对象,之后GcNotification对象立马失效。GC需要析构的时候,会调用GcNotification的析构函数,析构函数被调用后会执行CallBack函数(定义在MemoryCache),之后再次注册析构函数,循环往复的如此。所以当内存占用太高的时候,缓存会缩减缓存空间。
if (reRegister && !Environment.HasShutdownStarted)
{
GC.ReRegisterForFinalize(this);
}
注册析构函数
2,缓存对象(MemoryCache)的释放,没有对象引用缓存的话,难免GC会回收缓存对象。那么怎么避免缓存被GC回收?下面代码的思路还是不错的
~MemoryCache()
{
Dispose(false);
} public void Dispose()
{
Dispose(true);
} protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
GC.SuppressFinalize(this);
} _disposed = true;
}
} private void CheckDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException(typeof(MemoryCache).FullName);
}
}
缓存对象析构
3,IEntryLink对象的跨线程访问
缓存过期的时候,很可能不是本线程访问的,可能是另外一个线程,通过获取IEntryLink,之后通过IChangeToken对象通知缓存,所以不同线程间必须是可以共享IEntryLink对象。此处使用的是CallContext.LogicalGetData与CallContext.LogicalSetData。关于线程见数据通信,请参考“如何实现对上下文(Context)数据的统一管理”
internal static class EntryLinkHelpers
{
private const string ContextLinkDataName = "EntryLinkHelpers.ContextLink"; public static EntryLink ContextLink
{
get
{
var handle = CallContext.LogicalGetData(ContextLinkDataName) as ObjectHandle; if (handle == null)
{
return null;
} return handle.Unwrap() as EntryLink;
}
set
{
CallContext.LogicalSetData(ContextLinkDataName, new ObjectHandle(value));
}
} internal static IEntryLink CreateLinkingScope()
{
var parentLink = ContextLink;
var newLink = new EntryLink(parent: parentLink);
ContextLink = newLink;
return newLink;
} internal static void DisposeLinkingScope()
{
var currentLink = ContextLink;
var priorLink = ((EntryLink)currentLink).Parent;
ContextLink = priorLink;
}
}
EntryLinkHelpers代码示例
未完待续......
[Asp.net 5] Caching-缓存架构与源码分析的更多相关文章
- Caching-缓存架构与源码分析
Caching-缓存架构与源码分析 首先奉献caching的开源地址[微软源码] 1.工程架构 为了提高程序效率,我们经常将一些不频繁修改,但是使用了还很大的数据进行缓存.尤其是互联网产品,缓存可以说 ...
- MyBatis架构与源码分析<资料收集>
1.架构与源码分析 :https://www.cnblogs.com/luoxn28/p/6417892.html .https://www.cnblogs.com/wangdaijun/p/5296 ...
- Volley源码解析(三) 有缓存机制的情况走缓存请求的源码分析
Volley源码解析(三) 有缓存机制的情况走缓存请求的源码分析 Volley之所以高效好用,一个在于请求重试策略,一个就在于请求结果缓存. 通过上一篇文章http://www.cnblogs.com ...
- Spring Security 架构与源码分析
Spring Security 主要实现了Authentication(认证,解决who are you? ) 和 Access Control(访问控制,也就是what are you allowe ...
- 关于Asp.net core配置信息读取的源码分析梳理
概述 我们都知道asp.net core配置信息的读取离不开IConfigurationSource和IConfigurationProvider这两个类,ConfigurationSource可以提 ...
- java集合框架02——Collection架构与源码分析
Collection是一个接口,它主要的两个分支是List和Set.如下图所示: List和Set都是接口,它们继承与Collection.List是有序的队列,可以用重复的元素:而Set是数学概念中 ...
- Java 自动拆箱 装箱 包装类的缓存问题--结合源码分析
都0202 了 java 1.8 已经是主流 自动装箱 .拆箱已经很普遍使用了,那么有时候是不是会遇到坑呢? 我们先来看一段代码: public class TestWraperClass { pub ...
- Guava Cache 缓存实现与源码分析
目录 一.概述 1.内存缓存 2.核心数据结构 二.具体实现 0.一览众山小 1.CacheBuilder 构建器 2.LocalCache 一.概述 1.内存缓存 可看作一个jdk7的concurr ...
- jQuery源码分析系列
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...
随机推荐
- win8.1硬盘安装ubuntu14.04双系统
在网上找了很多方法都失败了,原因是大多数方法都是用mbr方式安装的,如grub4dos,easybcd.以至于连自己都怀疑win8能不能用硬盘安装,差点就去买个u盘来安装了,就在打算放弃的时候在ubu ...
- 代码的坏味道(21)——中间人(Middle Man)
坏味道--中间人(Middle Man) 特征 如果一个类的作用仅仅是指向另一个类的委托,为什么要存在呢? 问题原因 对象的基本特征之一就是封装:对外部世界隐藏其内部细节.封装往往伴随委托.但是人们可 ...
- Extjs 让combobox写起来更简单
也已经写了很久时间的extjs ,每次都用到很多的combobox,配置很多东西觉得实在是太麻烦,所以根据常用到的情况写了一个简便的combobox,再次记录下来,以免放在某个地方忘记了找不到了. 定 ...
- Impress.js上手 - 抛开PPT、制作Web 3D幻灯片放映
前言: 如果你已经厌倦了使用PPT设置路径.设置时间.设置动画方式来制作动画特效.那么Impress.js将是你一个非常好的选择. 用它制作的PPT将更加直观.效果也是嗷嗷美观的. 当然,如果用它来装 ...
- Oracle中的commit详解
本文转自 : http://blog.csdn.net/hzhsan/article/details/9719307 它执行的时候,你不会有什么感觉.commit在数据库编程的时候很常用,当你执行DM ...
- Spring.Net在Mvc4.0中应用的说明
案例Demo:http://yunpan.cn/cJ5aZrm7Uybi3 访问密码 414b Spring.Net在Mvc4.0中应用的说明 1.引用dll 2.修改Global文件 (Spring ...
- Chrome插件(Extensions)开发攻略
本文将从个人经验出发,讲述为什么需要Chrome插件,如何开发,如何调试,到哪里找资料,会遇到怎样的问题以及如何解决等,同时给出一个个人认为的比较典型的例子——获取网页内容,和服务器交互,再把信息反馈 ...
- C# 线程同步的三类情景
C# 已经提供了我们几种非常好用的类库如 BackgroundWorker.Thread.Task等,借助它们,我们就能够分分钟编写出一个多线程的应用程序. 比如这样一个需求:有一个 Winform ...
- CSharpGL(26)在opengl中实现控件布局/渲染文字
CSharpGL(26)在opengl中实现控件布局/渲染文字 效果图 如图所示,可以将文字.坐标轴固定在窗口的一角. 下载 CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入( ...
- jQuery 根据值或者文本选中select
今天因为有项目需要动态操作select选中 习惯在百度上搜了一下 ,结果还是挺多的.试了其中一个 发现不能使用.打开第2,3 个发现都是一样的然后自己稍微研究了一下 //初始化select,第一个选中 ...