[Asp.net5]Caching-缓存架构与源码分析

王朝学院·作者佚名  2016-08-28
窄屏简体版  字體: 小  |  中  |  大  |  超大  

首先奉献caching的开源地址[微软源码]

1.工程架构

[flash=500,400]http://s1.knowsky.com/20160211/eo4dilzo4yp00.png[/flash]

为了提高程序效率,我们经常将一些不频繁修改,但是使用了还很大的数据进行缓存。尤其是互联网产品,缓存可以说是提升效率优化第一利器。微软为我们实现了俩种缓存方式:内存缓存、分布式缓存。个人理解如果缓存在前端电脑内存的缓存叫做内存缓存,如果缓存在其它设备上,那么叫做分布式缓存。

俩种缓存方式的优缺点我开发程序经历过三个时间点,开始的时候从来不使用缓存,之后将数据缓存在内存中,最后使用分布式缓存。内存缓存的优点是速度快,缺点是内存损耗比较大,可能缓存的数据太大的时候就放不下了,另外一个缺点就是对于多前端程序的原则上是不支持的。而分布式缓存的优点是,理论上缓存大小没有上线,可以通过扩充物理硬件进行扩展,对于多前端支持的较好。

Microsoft.Framework.Caching.Abstractions

这个工程定义的是缓存的整体架构。我们的思想是面向接口编程,而不是面向实现编程。所以该工程定义了我们想要的接口

[flash=500,400]http://s1.knowsky.com/20160211/g0efzyyjr5q00.png[/flash]

从上图显而易见,微软将内存缓存和分布式缓存割裂开来,而不是我们一般意义上定义一个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

内存缓存的实现。此处代码结构如下图所示:

[flash=500,400]http://s1.knowsky.com/20160211/3r2dkbdhehi01.png[/flash]

大逻辑1,缓存太大时,压缩缓存空间(个人理解)

系统创建内存缓存对象(MemoryCache)的时候,同时创建GcNotification对象,之后GcNotification对象立马失效。GC需要析构的时候,会调用GcNotification的析构函数,析构函数被调用后会执行CallBack函数(定义在MemoryCache),之后再次注册析构函数,循环往复的如此。所以当内存占用太高的时候,缓存会缩减缓存空间。

[flash=500,400]http://s1.knowsky.com/20160211/go5jmjqklyc01.gif[/flash][flash=500,400]http://s1.knowsky.com/20160211/uwmvb32menw01.gif[/flash]if(reRegister && !Environment.HasShutdownStarted)

{

GC.ReRegisterForFinalize(this);

}

注册析构函数

2,缓存对象(MemoryCache)的释放,没有对象引用缓存的话,难免GC会回收缓存对象。那么怎么避免缓存被GC回收?下面代码的思路还是不错的

[flash=500,400]http://s1.knowsky.com/20160211/go5jmjqklyc01.gif[/flash][flash=500,400]http://s1.knowsky.com/20160211/uwmvb32menw01.gif[/flash]~MemoryCache()

{

Dispose(false);

}publicvoidDispose()

{

Dispose(true);

}protectedvirtualvoidDispose(booldisposing)

{if(!_disposed)

{if(disposing)

{

GC.SuppressFinalize(this);

}

_disposed=true;

}

}privatevoidCheckDisposed()

{if(_disposed)

{thrownewObjectDisposedException(typeof(MemoryCache).FullName);

}

}

缓存对象析构

3,IEntryLink对象的跨线程访问

缓存过期的时候,很可能不是本线程访问的,可能是另外一个线程,通过获取IEntryLink,之后通过IChangeToken对象通知缓存,所以不同线程间必须是可以共享IEntryLink对象。此处使用的是CallContext.LogicalGetData与CallContext.LogicalSetData。关于线程见数据通信,请参考“如何实现对上下文(Context)数据的统一管理”

[flash=500,400]http://s1.knowsky.com/20160211/go5jmjqklyc01.gif[/flash][flash=500,400]http://s1.knowsky.com/20160211/uwmvb32menw01.gif[/flash]internalstaticclassEntryLinkHelpers

{privateconststringContextLinkDataName ="EntryLinkHelpers.ContextLink";publicstaticEntryLink ContextLink

{get{varhandle = CallContext.LogicalGetData(ContextLinkDataName)asObjectHandle;if(handle ==null)

{returnnull;

}returnhandle.Unwrap()asEntryLink;

}set{

CallContext.LogicalSetData(ContextLinkDataName,newObjectHandle(value));

}

}internalstaticIEntryLink CreateLinkingScope()

{varparentLink =ContextLink;varnewLink =newEntryLink(parent: parentLink);

ContextLink=newLink;returnnewLink;

}internalstaticvoidDisposeLinkingScope()

{varcurrentLink =ContextLink;varpriorLink =((EntryLink)currentLink).Parent;

ContextLink=priorLink;

}

}

EntryLinkHelpers代码示例

未完待续......

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航