如何解决ASP.NET和SQL Server之间的连接池问题?

最近几天我们在我们的网站上看到这个错误消息太多了:

“Timeout expired。在从池中获取连接之前已经超时了,这可能是因为所有连接池都在使用中,并且达到最大池大小。

我们在一段时间内没有改变我们的代码中的任何东西。 我修改了代码来检查打开的连接没有closures,但发现一切正常。

  • 我该如何解决这个问题?

  • 我需要编辑这个池吗?

  • 如何编辑此池的最大连接数?

  • 高stream量网站的build议价值是多less?


更新:

我需要在IIS中编辑一些东西吗?

更新:

我发现活动连接的数量是从15到31的任何地方,我发现在SQL服务器中configuration的连接的最大允许数量超过3200个连接,是31太多,或者我应该编辑ASP.NET configration ?

在大多数情况下,连接池问题与“连接泄漏”有关。 您的应用程序可能不会正确和一致地closures其数据库连接。 当您打开连接时,它们将保持阻塞状态,直到.NET垃圾收集器通过调用它们的Finalize()方法closures它们为止。

你想确保你真的closures了连接 。 例如,如果.OpenClose之间的代码引发exception,则以下代码将导致连接泄漏:

 var connection = new SqlConnection(connectionString); connection.Open(); // some code connection.Close(); 

正确的方法是这样的:

 var connection = new SqlConnection(ConnectionString); try { connection.Open(); someCall (connection); } finally { connection.Close(); } 

要么

 using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); someCall(connection); } 

当你的函数从一个类方法返回一个连接时,确保你在本地caching并调用它的Close方法。 您将使用此代码泄漏连接,例如:

 var command = new OleDbCommand(someUpdateQuery, getConnection()); result = command.ExecuteNonQuery(); connection().Close(); 

从第一次调用getConnection()返回的连接没有被closures。 而不是closures你的连接,这条线创build一个新的,并试图closures它。

如果您使用SqlDataReaderOleDbDataReader ,closures它们。 即使closures连接本身似乎也有诀窍,但在使用它们时要特别closures数据读取器对象。


MSDN / SQL杂志中的这篇文章“ 为什么连接池溢出? ”解释了很多细节并提出了一些debugging策略:

  • 运行sp_whosp_who2 。 这些系统存储过程从sysprocesses系统表中返回信息,显示所有工作进程的状态和信息。 通常,每个连接都会看到一个服务器进程ID(SPID)。 如果您使用连接string中的“应用程序名称”参数来命名连接,则您的工作连接将很容易find。
  • 使用SQL Server Profiler和SQLProfiler TSQL_Replay模板来跟踪打开的连接。 如果您熟悉Profiler,则此方法比使用sp_who进行轮询更容易。
  • 使用性能监视器来监视池和连接。 我稍后讨论这个方法。
  • 用代码监视性能计数器。 您可以通过使用例程提取计数器或使用新的.NET PerformanceCounter控件来监视连接池的健康状况和build立的连接数。

在安装.NET Framework v4.6.1后, 由于此更改,我们与远程数据库的连接立即开始超时。

要修复,只需在连接string中添加参数TransparentNetworkIPResolution并将其设置为false

服务器= myServerName;数据库= MyDatabase的; Trusted_Connection = TRUE; TransparentNetworkIPResolution =假

除非你的使用量增加很多,否则似乎不太可能只有积压的工作。 国际海事组织,最有可能的select是,有些东西正在使用连接,而不是及时发布。 你确定你在使用所有的情况吗? 或者(通过任何机制)释放连接?

您是否在closures连接或数据读取器之前检查没有closures的DataReader和response.redirects。 在redirect之前不要closures它们时,连接保持打开状态。

我们不时在我们的网站上遇到这个问题。 在我们的情况下,罪魁祸首是我们的统计/索引越来越过时。 这会导致以前快速运行的查询(最终)变慢和超时。

尝试更新统计信息和/或重build受查询影响的表上的索引,看看是否有帮助。

您可以通过在连接string中指定MinPoolSize=xyz和/或MaxPoolSize=xyz来指定最小和最大池大小。 这个问题的原因可能是另一回事。

在我的一个.NET应用程序中使用某些第三方数据层时,我也遇到了这个问题。 问题在于该层没有正确closures连接。

我们抛出了层,并创build了一个自己,总是closures和configuration连接。 从那以后,我们不再犯错误了。

用这个:

 finally { connection.Close(); connection.Dispose(); SqlConnection.ClearPool(); } 

如果您正在使用复杂的遗留代码(使用简单的使用(..){..})是不可能的 – 就像我一样 – 您可能需要查看我在这个SO问题中发布的代码片段,以确定在连接可能泄漏时调用连接创build堆栈(在设置超时后不closures)。 这使得发现泄漏的原因相当容易。

这主要是由于应用程序中的连接没有closures。 在连接string中使用“MinPoolSize”和“MaxPoolSize”。

不要多次实例化sql连接。 打开一个或两个连接,并将其用于所有下一个SQL操作。

似乎即使在抛出连接时抛出exception。

在我的情况下,我没有closuresDataReader对象。

  using (SqlCommand dbCmd = new SqlCommand("*StoredProcedureName*")) using (dbCmd.Connection = new SqlConnection(WebConfigurationAccess.ConnectionString)) { dbCmd.CommandType = CommandType.StoredProcedure; //Add parametres dbCmd.Parameters.Add(new SqlParameter("@ID", SqlDbType.Int)).Value = ID; ..... ..... dbCmd.Connection.Open(); var dr = dbCmd.ExecuteReader(); //created a Data reader here dr.Close(); //gotta close the data reader //dbCmd.Connection.Close(); //don't need this as 'using' statement should take care of this in its implicit dispose method. } 

你的代码泄露了连接。 您可以尝试使用来certificate您正在closures它们。

  Using (SqlConnection sqlconnection1 = new SqlConnection(“Server=.\\SQLEXPRESS ;Integrated security=sspi;connection timeout=5”)) { sqlconnection1.Open(); SqlCommand sqlcommand1 = sqlconnection1.CreateCommand(); sqlcommand1.CommandText = “raiserror ('This is a fake exception', 17,1)”; sqlcommand1.ExecuteNonQuery(); //this throws a SqlException every time it is called. sqlconnection1.Close(); //Still never gets called. } // Here sqlconnection1.Dispose is _guaranteed_ 

https://blogs.msdn.microsoft.com/angelsb/2004/08/25/connection-pooling-and-the-timeout-expired-exception-faq/

这个问题我以前遇到过。 它最终成为了防火墙的一个问题。 我刚刚添加了一个规则到防火墙。 我不得不打开端口1433所以SQL服务器可以连接到服务器。

这个问题我在我的代码。 我将粘贴一些示例代码,我已经结束了错误。 在从池中获取连接之前已经超时。 发生这种情况的原因可能是因为所有连接池都在使用中,并且达到最大池大小。

  String query = "insert into STATION2(ID,CITY,STATE,LAT_N,LONG_W) values('" + a1 + "','" + b1 + "','" + c1 + "','" + d1 + "','" + f1 + "')"; //,'" + d1 + "','" + f1 + "','" + g1 + "' SqlConnection con = new SqlConnection(mycon); con.Open(); SqlCommand cmd = new SqlCommand(); cmd.CommandText = query; cmd.Connection = con; cmd.ExecuteNonQuery(); **con.Close();** 

您想每次closures连接。 在此之前,我没有closures连接,因为我得到了错误。 加了closures声明后,我已经结束了这个错误