使用多个MemoryCache实例


72

我想使用System.Runtime.Caching名称空间向我的应用程序添加缓存功能,并且可能要在多个地方和不同的上下文中使用缓存。为此,我想使用几个MemoryCache实例。

但是,我在这里建议不要使用多个以上的MemoryCache实例:

MemoryCache不是单例,但是您应该仅创建几个或可能仅创建一个MemoryCache实例,并且用于缓存项目的代码应使用这些实例。

多个MemoryCache实例将如何影响我的应用程序?我觉得这很奇怪,因为在我看来,在应用程序中使用多个缓存是很常见的情况。

编辑:更具体地说,我有一个应该为每个实例保留缓存的类。我应该避免使用MemoryCache并寻找其他缓存解决方案吗?MemoryCache在这种情况下使用是否被认为是不好的?如果是,为什么?


1
单个缓存和多个缓存之间有什么区别?毕竟,他们都将做同一件事。
支出者

12
首先,我不必担心按键碰撞。另外,我相信它比拥有一个可以容纳应用程序缓存的所有对象的对象更有组织性,并且更容易调试。
阿迪·莱斯特

5
这意味着您不应创建许多确实缓存同一事物的缓存。最好由一个中央缓存来尽可能多地缓存。但是完全可以创建许多可以缓存不同内容的缓存。
阿洛伊斯·克劳斯

如果您对分布式缓存感兴趣,则可以了解Windows AppFabric缓存。Win 2008附带了一个功能,它提供了一个功能更强大的缓存系统,该系统可以利用外部服务器。这是一篇关于此的文章hanselman.com/blog/…– agarcian 2011
23

11
我也用几个。通常每种类型一个。如果说“您应该...”的文档说“您应该...因为...”,那肯定是很棒的。
Kit

Answers:


74

我最近也亲自经历了这个。考虑到内存中缓存将是特定于进程的(不在网站,本机业务应用程序或多个服务器的多个实例之间共享),MemoryCache除了代码组织方面的原因(使用其他方式可以实现)之外,拥有多个实例确实没有任何好处。

内存高速缓存旨在单独使用,主要是因为其具有内存管理功能。除了性能计数器(确实有一些开销)之外,MemoryCache还可以在分配的内存用完时使项目过期。

如果缓存的当前实例超出了CacheMemoryLimit属性设置的内存限制,则缓存实现将删除缓存条目。应用程序中的每个缓存实例都可以使用CacheMemoryLimit属性指定的内存量。

来自MemoryCache.CacheMemoryLimit属性

通过仅使用MemoryCache的一个实例,它可以在整个应用程序实例中有效地应用此内存管理。在整个应用程序中使最不重要的项目过期。这样可确保最大程度地使用内存,而不会超出您的硬件功能。通过限制任何一个MemoryCache的范围(如类的一个实例),它不再能够有效地管理应用程序的内存(因为它无法“看到”所有内容)。如果所有这些高速缓存都“忙”着,那么您可能很难管理内存,而且效率永远也不会如此高。

这对于没有专用服务器那么豪华的应用程序特别敏感。想象一下,您正在共享服务器上运行应用程序,其中仅分配了150mb RAM(通常便宜的$ 10 /月托管),您需要依靠缓存来最大程度地使用它而不超过它。如果超出此内存使用量,则您的应用程序池将被回收,并且您的应用程序将丢失所有内存缓存!(常见的廉价托管做法),这同样适用于在某些共享公司服务器上内部托管的非Web应用程序。同样的交易,您被告知不要占用该计算机上的所有内存,并与其他一些业务应用程序和平共处。

内存限制,应用程序池回收,丢失缓存是Web应用程序常见的“致命弱点”。当应用程序最繁忙时,由于超出内存分配,它们丢失了所有缓存条目,因此重置频率最高,因此,大多数工作是重新获取本应缓存的内容。这意味着该应用实际上在最大负载下会失去性能,而不是获得性能。

我知道MemoryCache是​​System.Web.Caching.Cache实现的非Web特定版本,但这说明了缓存实现的逻辑。如果您没有排他性地使用硬件,则相同的逻辑可以应用于非Web项目。请记住,如果您的缓存迫使计算机开始进行页面文件交换,那么您的缓存将不再比在磁盘上进行缓存更快。即使某个限制为2gb或类似的值,您总会在某个地方想要一个限制。

以我为例,在阅读了有关此内容的内容后,我切换到在我的应用程序中使用一个“公共静态MemoryCache”,并仅通过其缓存键将缓存的项目分开。例如,如果要在每个实例上缓存,则可以具有一个类似“ instance- {instanceId} -resourceName- {resourceId}”之类的缓存键。可以将其视为间隔缓存条目的名称。

希望有帮助!


2
谢谢,这很有帮助。但是,我并不是要根据内存大小来限制我的缓存,而可能要根据容量来限制-我希望每个实例都具有一定的容量,并且我不在乎合并的缓存。在这种情况下,通过命名约定来分隔缓存项是不合适的,并且似乎有些强制。
阿迪·莱斯特

1
@AdiLester您已经发现了它。理想情况下,Microsoft将为其实现缓存“区域”,MemoryCache以便您不需要这些强制的“命名空间”键,并且可以查询任何Region中缓存的项目数。但是,当前非Web缓存实现不支持该功能。:-(与此同时听起来像是你知道你的限制,并确定他们。
BenSwayne

您能否显示一些代码示例,以说明上述用法相对于单实例的好处。在这种情况下,它将变得更加有用和流行。
Imad Alazani

极好的答案。他们应该将此添加到他们的文档中!
jleach,2013年

6

我也用几个。通常每种类型一个。

看一下MemoryCacheI,它会挂接到AppDomain事件中并维护性能计数器。我怀疑然后会使用多个资源(例如CPU,计数器和内存),从而在资源上产生一些开销,这就是为什么不鼓励这样做的原因。


然后,为什么不“提升”其功能并至少允许您使用不同的规则创建一个级别的子类别。现在,我最多有两个缓存(因此找到了这个问题)。图像缓存,其中有我要受内存限制的大对象,并且几乎也不会过期-以及用于验证USPS地址的微小缓存,因此,如果有人在15分钟内继续验证相同的地址,我希望它不会继续命中三分之一派对服务。这很有趣,因为我发现自己想要更简单或更复杂的东西来解决相同的问题。
Simon_Weaver
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.