最近几天,我们经常在网站上看到这样的错误信息:

“超时过期。超时时间 在获取 来自池的连接。这可能 已经发生是因为全部池化了吗 连接正在使用,马克斯泳池 规模达到了。”

我们已经有一段时间没有更改代码中的任何内容了。我修改了代码以检查未关闭的打开连接,但发现一切正常。

我怎么解决这个问题? 我需要编辑这个池吗? 如何编辑此池的最大连接数? 高流量网站的推荐值是多少?


更新:

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

更新:

我发现活动连接的数量在15到31之间,我发现在SQL server中配置的最大允许连接数超过3200个连接,是31太多了还是我应该在ASP中编辑一些东西。网络配置?


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


除非您的使用量增加了很多,否则不太可能只是有工作积压。在我看来,最有可能的选择是某些东西正在使用连接,并且没有及时释放它们。你确定你在所有情况下都使用了using吗?或者(通过任何机制)释放连接?


您是否检查了未关闭和响应的数据阅读器。在关闭连接或数据读取器之前重定向。如果在重定向之前不关闭连接,则连接将保持打开状态。


当我在一个。net应用程序中使用一些第三方数据层时,我也遇到过这个问题。问题是该层没有正确地关闭连接。

我们扔掉了这个层,自己创建了一个,它总是关闭和处理连接。从那以后,我们就不会再得到错误了。


在大多数情况下,连接池问题与连接泄漏有关。应用程序可能无法正确且一致地关闭数据库连接。当您保持连接打开时,它们将保持阻塞状态,直到. net垃圾回收器通过调用Finalize()方法为您关闭它们。

你要确保你真的关闭了连接。例如,如果.Open和Close之间的代码抛出异常,下面的代码将导致连接泄漏:

var connection = new SqlConnection(connectionString);

connection.Open();
// some code
connection.Close();                

正确的方法是这样的:

var connection = new SqlConnection(ConnectionString);

try
{
     connection.Open();
     someCall (connection);
}
finally
{
     connection.Close();                
}

or

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

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

var command = new OleDbCommand(someUpdateQuery, getConnection());

result = command.ExecuteNonQuery();
connection().Close(); 

第一次调用getConnection()返回的连接没有被关闭。这一行不会关闭连接,而是创建一个新的连接并尝试关闭它。

如果您使用SqlDataReader或OleDbDataReader,请关闭它们。尽管关闭连接本身似乎就能达到目的,但在使用数据读取器对象时,还是要花费额外的精力显式关闭它们。


这篇来自MSDN/SQL杂志的文章“为什么连接池溢出?”解释了很多细节,并建议了一些调试策略:

Run sp_who or sp_who2. These system stored procedures return information from the sysprocesses system table that shows the status of and information about all working processes. Generally, you'll see one server process ID (SPID) per connection. If you named your connection by using the Application Name argument in the connection string, your working connections will be easy to find. Use SQL Server Profiler with the SQLProfiler TSQL_Replay template to trace open connections. If you're familiar with Profiler, this method is easier than polling by using sp_who. Use the Performance Monitor to monitor the pools and connections. I discuss this method in a moment. Monitor performance counters in code. You can monitor the health of your connection pool and the number of established connections by using routines to extract the counters or by using the new .NET PerformanceCounter controls.


在我们的网站上,我们也不时地遇到这个问题。在我们的案例中,罪魁祸首是我们的统计数据/索引过时了。这将导致先前快速运行的查询(最终)变慢并超时。

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


如果您正在处理复杂的遗留代码,只需使用(..){..}是不可能的-正如我所做的那样-您可能想要查看我在这个SO问题中发布的代码片段,以确定当连接可能泄漏(在设置超时后未关闭)时连接创建的调用堆栈。这使得发现泄漏的原因相当容易。


这主要是由于应用程序中没有关闭连接。使用“MinPoolSize”和“MaxPoolSize”连接字符串。


用这个:

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

在我的例子中,我没有关闭DataReader对象。

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.
}

在安装。net Framework v4.6.1时,由于这个更改,我们到远程数据库的连接立即开始超时。

要修复这个问题,只需在连接字符串中添加参数transparentnetworkipressolution,并将其设置为false:

服务器= myServerName;数据库= myDataBase; Trusted_Connection = True; TransparentNetworkIPResolution = False


不要实例化sql连接太多次。打开一个或两个连接,并将它们用于接下来的所有sql操作。

似乎即使在处置连接时也会抛出异常。


您已经泄漏了代码上的连接。您可以尝试使用using来证明您正在关闭它们。

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();**

您希望每次都关闭连接。在此之前,我没有我们关闭连接,由于这个我得到了错误。 添加结束语句后,我已经克服了这个错误


你也可以尝试一下,解决超时问题:

如果你没有在你的webconfig中添加httpRuntime,在<system中添加。网络>标记

<sytem.web>
     <httpRuntime maxRequestLength="20000" executionTimeout="999999"/>
</system.web>

and

像这样修改你的连接字符串;

 <add name="connstring" connectionString="Data Source=DSourceName;Initial Catalog=DBName;Integrated Security=True;Max Pool Size=50000;Pooling=True;" providerName="System.Data.SqlClient" />

最后使用

    try
    {...} 
    catch
    {...} 
    finaly
    {
     connection.close();
    }

除了公布的解决方案。

在处理1000页遗留代码时,每个代码都多次调用公共GetRS,这里有另一种解决问题的方法:

在现有的公共DLL中,我们添加了CommandBehavior。CloseConnection选择:

static public IDataReader GetRS(String Sql)
{
    SqlConnection dbconn = new SqlConnection(DB.GetDBConn());
    dbconn.Open();
    SqlCommand cmd = new SqlCommand(Sql, dbconn);
    return cmd.ExecuteReader(CommandBehavior.CloseConnection);   
}

然后,在每个页面中,只要关闭数据读取器,连接也会自动关闭,从而防止连接泄漏。

IDataReader rs = CommonDLL.GetRS("select * from table");
while (rs.Read())
{
    // do something
}
rs.Close();   // this also closes the connection

在我的情况下,我有无限循环(从一个get属性试图从数据库中获取值),不断打开数百个Sql连接。

要重现这个问题,试试这个:

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

我也有同样的问题,想要分享帮助我找到源头的东西: 将应用程序名称添加到连接字符串中,然后监视到SQL Server的打开连接

select st.text,
    es.*, 
    ec.*
from sys.dm_exec_sessions as es
    inner join sys.dm_exec_connections as ec on es.session_id = ec.session_id
    cross apply sys.dm_exec_sql_text(ec.most_recent_sql_handle) st
where es.program_name = '<your app name here>'

是的,有一种方法可以改变配置。如果你在一个专用的服务器上,只是需要更多的SQL连接,你可以在两个连接字符串中更新“最大池大小”条目,按照下面的说明:

Log into your server using Remote Desktop Open My Computer (Windows - E) and go to C:\inetpub\vhosts[domain]\httpdocs Double click on the web.config file. This may just be listed as web if the file structure is set to hide extensions. This will open up Visual Basic or similar editor. Find your Connection Strings, these will look similar to the examples below : "add name="SiteSqlServer" connectionString="server=(local);database=dbname;uid=dbuser;pwd=dbpassword;pooling=true;connection lifetime=120;max pool size=25;""

5.将最大池大小=X值更改为所需的池大小。

保存并关闭你的网页。配置文件。


确保您为连接池设置了正确的设置。这是非常重要的,正如我在下面的文章中解释的那样: https://medium.com/@dewanwaqas/configurations-that-significantly-improves-your-app-performance-built-using-sql-server-and-net-ed044e53b60 如果遵循该方法,您将看到应用程序的性能有了极大的改善。


在我的例子中还发生了另一个原因,因为使用async/await,导致了相同的错误消息:

系统。InvalidOperationException: '超时。从池中获取连接之前的超时时间。这可能是因为所有池连接都在使用中,且池大小已达到最大。”

只是对发生了什么(以及我是如何解决它的)的一个快速概述,希望这将在未来帮助其他人:

找出原因

这一切都发生在ASP中。NET Core 3.1 web项目与Dapper和SQL Server,但我认为它是独立于这种类型的项目。

首先,我有一个中心函数给我SQL连接:

internal async Task<DbConnection> GetConnection()
{
    var r = new SqlConnection(GetConnectionString());
    await r.OpenAsync().ConfigureAwait(false);
    return r;
}

我在几十个方法中使用这个函数,例如:

public async Task<List<EmployeeDbModel>> GetAll()
{
    await using var conn = await GetConnection();
    var sql = @"SELECT * FROM Employee";

    var result = await conn.QueryAsync<EmployeeDbModel>(sql);
    return result.ToList();
}

正如您所看到的,我使用的是没有花括号({,})的new using语句,因此连接的处理是在函数的末尾完成的。

尽管如此,我还是得到了关于池中没有更多可用连接的错误。

我开始调试我的应用程序,并让它在异常发生时停止。当它停止时,我首先看了一下调用堆栈窗口,但这只显示了System.Data中的某个位置。SqlClient,并不是真正的帮助我:

接下来,我看了看Tasks窗口,这是一个更好的帮助:

在“等待”或“计划”状态下,对我自己的GetConnection方法的调用确实有数千次。

当在任务窗口中双击这样的一行时,它通过调用堆栈窗口向我显示了我的代码中的相关位置。

这帮助我找到了这种行为的真正原因。它在下面的代码中(只是为了完整性):

[Route(nameof(LoadEmployees))]
public async Task<IActionResult> LoadEmployees(
    DataSourceLoadOptions loadOption)
{
    var data = await CentralDbRepository.EmployeeRepository.GetAll();

    var list =
        data.Select(async d =>
            {
                var values = await CentralDbRepository.EmployeeRepository.GetAllValuesForEmployee(d);
                return await d.ConvertToListItemViewModel(
                    values,
                    Config,
                    CentralDbRepository);
            })
            .ToListAsync();
    return Json(DataSourceLoader.Load(await list, loadOption));
}

在上面的控制器操作中,我首先调用EmployeeRepository.GetAll()从数据库表“Employee”中获得模型列表。

然后,对于每个返回的模型(即结果集的每一行),我再次对employeerepository . getallvaluesforeemployee (d)进行数据库调用。

虽然这在性能方面非常糟糕,但在异步上下环境中,它的行为方式是占用连接池连接而不适当地释放它们。

解决方案

我通过在外部SQL查询的内部循环中删除SQL查询来解决这个问题。

这应该通过完全省略它来完成,或者如果需要,将它移动到外部SQL查询中的一个/多个lpe join,以便在一个SQL查询中获得数据库中的所有数据。

吸取的教训

不要在短时间内执行大量SQL查询,特别是在使用async/await时。


我也面临着同样的问题,经过几个小时的研究,我意识到我是在没有VPN的Guest网络上连接的,所以设置VPN对我来说很管用


我在AWS EC2实例上也得到了这个确切的错误日志。

因为我只是部署alpha应用程序(没有真正的用户),所以没有出现连接泄漏,而且我向Activity Monitor和sp_who确认实际上没有到数据库的连接。

我的问题与AWS有关——更具体地说,与安全组有关。只有特定的安全组可以访问我存放数据库的RDS服务器。 我使用authorization -security-group-ingress命令添加了一个入口规则,允许使用——source-group-name参数访问RDS服务器的正确EC2实例。添加了入口规则,我可以在AWS UI上看到-但我得到了这个错误。

当我在AWS UI上手动删除并添加入口规则时,突然异常不再,应用程序正在工作。


起初我并不认为这是我的问题,但在浏览这个列表时,我发现它并没有涵盖我的问题。

我的问题是,我有一个错误,它试图写相同的记录多次使用实体框架。它不应该这样做;那是我的bug。看看你正在写的数据。我的想法是SQL正在忙着写记录,可能是锁定和创建超时。在我修复了试图在连续尝试中写入记录倍数的代码区域之后,错误就消失了。


对于EntityFramework 这可能是连接过载的情况。你只需要修复连接字符串添加这个字段到连接字符串:

=> Max Pool Size=200

例子:

<add name="DataProvider" connectionString="Data Source=.;Initial Catalog=dbname;User ID=dbuser;Password=dbpassword;Max Pool Size=200" providerName="System.Data.SqlClient" />

您需要告诉数据库服务器在卸载页面时关闭连接。

protected void Page_Unload(object sender, EventArgs e) {
    if (qryCnn != null) 
        qryCnn.Close();
}

对于我来说,使用实体框架,我错过了可以简化using语句的智能感知建议。 我错误地简化了using语句

ie

using (var db = new MyDbContext()){}

化简为

using var db = new MyDbContext();

not

var db = new MyDbContext();