背景
我正在比较在IIS 7(在Windows 7主机上测试)下运行的NancyFx和ServiceStack.NET的性能。两者都非常快-在本地测试时,每个框架处理超过10,000次/秒的请求,其中ServiceStack大约快了20%。
我遇到的问题是,ASP.NET似乎会缓存HttpHandler每个唯一URI请求的响应,很快就会导致巨大的内存压力(3+ GB)并且使垃圾收集器过载(GC耗时25%)。到目前为止,我无法禁用缓存和对象的积累,并正在寻求有关如何禁用此行为的建议。
细节
请求循环基本上如下:
for i = 1..100000:
string uri = http://localhost/users/{i}
Http.Get(uri)
响应是一个简单的JSON对象,格式为{ UserID: n }。我已经打开了WinDBG,对于每个请求,有以下内容:
- 一个 System.Web.FileChangeEventHandler - 两个 System.Web.Configuration.MapPathCacheInfos - 两个 System.Web.CachedPathDatas - 三个 System.Web.Caching.CacheDependencys - 五个 System.Web.Caching.CacheEntrys
显然,这些缓存项让我相信这是一个缓存膨胀问题(我希望能够摆脱150,000个无用的对象!)。
我已经尝试过:
- 在IIS“HTTP响应标头”中,将“过期Web内容”设置为“立即”。 - 在web.config中
<system.web>
<caching>
<outputCache enableOutputCache="false" enableFragmentCache="false"/>
</caching>
</system.web>
同样也可以在web.config文件中进行配置(还有很多政策的变体,包括不配置)。
<caching enabled="false" enableKernelCache="false">
<profiles>
<add policy="DontCache" kernelCachePolicy="DontCache" extension="*/>
</profiles>
</caching>
查看了框架的源代码,看是否内置了使用ASP.NET缓存的“特性”。虽然有缓存助手,但它们是私有的,不会利用ASP.NET缓存。
更新 #1
通过反射器深入挖掘后,我发现将UrlMetadataSlidingExpiration
的值设置为零可以消除大量过度的内存使用,但吞吐量会降低50%(当UrlMetadataSlidingExpiration
非零时,FileAuthorizationModule类会缓存FileSecurityDescriptors,这可能相对昂贵)。
这可以通过更新web.config并放置以下内容来实现:
<hostingEnvironment urlMetadataSlidingExpiration="00:00:00"/>
我将尝试完全禁用FileAuthorizationModule的运行(如果可能的话)来查看是否有所帮助。然而,ASP.NET仍会生成2*N个MapPathCacheInfo
和CacheEntry
对象,因此内存仍将被占用,只是速度慢了很多。
更新#2
问题的另一半与此处描述的问题相同:Prevent many different MVC URLs from filling ASP.NET Cache。设置
<cache percentagePhysicalMemoryUsedLimit="1" privateBytesPollTime="00: 00: 01"/>
可以有所帮助,但即使使用这些非常激进的设置,内存使用也会迅速上升到2.5GB(相对于4GB)。理想情况下,这些对象本身就不应该被创建。如果失败,我可能会采用反射的hacky解决方案来清除缓存(所有这些条目都是“私有”的,在枚举公共缓存时不会列举它们)。