ADO.NET连接池无法重用连接。

3
我正在开发一个使用EF 6.x连接Azure SQL数据库的ASP.NET MVC应用程序。最近由于负载增加,该应用程序开始进入无法与SQL服务器通信的状态。我可以使用exec sp_who查看到有100个活动连接到我的数据库,任何新连接都无法创建,并显示以下错误消息:

System.Data.Entity.Core.EntityException: 潜在提供程序“System.Data.SqlClient”失败。 ---> System.InvalidOperationException: 超时已过期。 在从池中获取连接之前已经超时。这可能是因为所有池化的连接都在使用并且达到了最大池大小。

大部分时间,该应用程序的平均活动连接数为10至20个。任何负载都不会改变这个数字...即使负载很高,它也会保持在10-20的水平。但在某些情况下,它可能会在不到一分钟的时间内达到100,而没有任何逐渐增加的时间,这会导致应用程序处于所有请求失败的状态。所有这些100个连接都处于睡眠状态和等待命令
好的一面是,我找到了一个解决方法来缓解这个问题-从客户端清除连接池。我使用SqlCoonection.ClearAllPools(),它会立即关闭所有连接,然后sp_who会显示我通常的10-20个连接。
坏的一面是,我仍然不知道根本原因。
只是为了澄清,该应用程序负载大约为200-300并发用户,每分钟生成1000个请求。
通过@DavidBrowne的绝妙建议,使用简单模式来跟踪泄漏的连接,在配置Owin引擎时,我能够找到泄漏的连接。
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
    // here in create method I'm creating also a connection leak tracker
    app.CreatePerOwinContext(() => MyCoolDb.Create());
    ...
}

基本上,在每个请求中,Owin都会创建一个连接并且不释放它,当WebAPI的负载增加时我遇到了问题。
这可能是真正的原因,那么我是否可以相信Owin足够聪明,能够在需要时惰性地创建连接(使用提供的函数),并在使用后释放连接呢?

你是否排除了数据库中的瓶颈、锁升级等问题?可能是由于长时间运行的进程占用了某些资源,导致请求队列等待。在连接建立期间是否进行了索引重建或其他维护操作? - Ross Bush
你确定这不是预期的吗?为什么不在连接字符串中更改“最大池大小”值? - Simon Mourier
@JohnWu 是的,唯一的连接字符串,唯一的连接池(所有参数相同),流程也是一样的 using(var db = new MyDbContext()) { ... } - Mando
@SimonMourier 这绝对不是预期的行为,活动连接数在10秒内从10跳到200。假设该应用程序可以处理80%的负载,具有大约10个活动连接,但一旦达到100%,我可能会在每小时左右的某个时候经历一个突然跳转到200个连接的10秒期间。 - Mando
2
有没有其他系统使用这个数据库,特别是报告或自定义查询?只需要一个运行时间长且隔离级别错误的报告,就可能会出现页面/表/索引锁定,从而阻塞所有连接。一旦它们被阻塞,它们就会迅速堆积。检查SQL日志以查找任何可疑的非站点用户。 - John Wu
显示剩余6条评论
1个回答

1

这是一个非常好的建议,使用这种助手可以找到连接泄漏问题。我一定会尝试的。 - Mando
我已经更新了我的问题,我发现了一个可能是原因的连接泄漏。尽管如此,我会继续研究。 - Mando
你发现了什么问题,@AlexeyStrakh?我也遇到了同样的问题。Web Api 2 + OWIN + Identity。泄漏检测器只显示在启动时注册ApplicationDbContext。网站运行正常,但在压力测试中,所有的SQL连接都会在几秒钟内消失。 - Raptor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接