这将是一个很长的帖子,所以请和我在一起。
几个月前我们在这里实施的生产站点之一,我开始经常在我们的 ELMAH 日志中看到可怕的连接泄漏错误消息。
"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached."
这让我感到困惑,因为我们使用的是 EF,并且连接处理应该是自动的。
于是我开始挖掘。我考虑的第一个潜在罪魁祸首是 MiniProfiler(或者我应该说,我们使用 miniprofiler 的实现)。我们一直在使用它,它运行良好,但我担心潜在的连接泄漏。
public OurContext() : base(GetProfilerConnection(), true)
{}
private static DbConnection GetProfilerConnection()
{
return new EFProfiledDbConnection(new SqlConnection(ConfigurationManager.ConnectionStrings["Database"].ConnectionString),
MiniProfiler.Current);
}
我的印象是基本调用中的“真实”参数导致上下文获取连接的所有权,所以我相信这应该可以正常工作并且连接将被处理掉。
在我们的 Enhancement DEV 分支中,我删除了 miniprofiler,因为它尚未更新以支持 EF5,并且我们将在不久的将来某个时候进行迁移,因此应该将其作为一个问题删除。
关注点二是“我们是否正确地处理了我们的数据上下文”?因此,我下载了 Entity Framework Profiler 进行试用,并拿了我们最重的页面并进行了测试。
结果明确表明,我们打开的任何上下文都是关闭的,但对我而言,相关的部分是我们打开的上下文的数量。我们有我们的 DI 容器(Ninject 2)设置来为每个 Web http 请求建立一个上下文,我认为这是正确的。问题在于我们如何在应用程序中处理图像。特别是这个页面在数据库中最多可以有七个图像。这些图像中的每一个都通过 MVC 操作包含在页面中。像这样:
[<img src="/Controller/GetPhotoAction/[ImageId] />]
由于图像是单独的请求,因此正在打开单独的上下文。因此,对于这个特定页面,如果我理解正确的话,我们将使用连接池中的七个不同连接。将其乘以多少用户,我就会看到上面的错误消息是如何正确的。
将图像存储在数据库中的原因有两个。一,我们用于管理此应用程序数据的管理应用程序位于美国西海岸,但托管该应用程序的服务器位于美国东海岸。我们在西海岸工作的网络和东海岸的服务器之间有一条 VPN 隧道。该应用程序也是负载平衡的(2 个 Web 前端)。决定将图像存储在数据库中,以避免通过 VPN 隧道复制图像,然后处理将图像写入每个服务器上 Web 应用程序内的文件位置的权限(这两个位置也是完全不同的域) .
在此期间,我们在测试期间提高了连接字符串中的最大连接池大小,并将在下周初将其部署到 PROD。
所以,我的问题是:
1) 我是否在这里进行了泄漏检查?我相信我有。我在上面所说的任何事情上都错了吗?
2)如果这个页面上的多个数据上下文被证明是罪魁祸首,关于如何将图像写入全国两台服务器的建议,记住权限会跨域?实际上,我想这样做,但是技术障碍比我们在假期前的这个时候愿意做的要多一些。
3)如果您认为以上都不是问题,我会遗漏什么?难道真的是请求足够高以至于我们遇到了这个错误并且我们需要向外扩展?我可以挖掘日志来查看使用统计信息,但似乎不太可能。此页面缓存一个小时(参数不同)