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

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

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

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

  • 我怎么解决这个问题?

  • 我需要编辑这个池吗?

  • 我如何编辑这个池的最大连接数?

  • 高流量网站的推荐值是多少?


更新:

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

更新:

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

582326 次浏览

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

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

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

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

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

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

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

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);
}

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

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


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

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

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


本文"为什么连接池溢出?"from MSDN/SQL Magazine解释了很多细节,并建议了一些调试策略:

  • 运行sp_whosp_who2。这些系统存储过程返回来自sysprocesses系统表的信息,这些信息显示了所有工作进程的状态和信息。通常,每个连接有一个服务器进程ID (SPID)。如果您使用连接字符串中的应用程序名称参数来命名连接,那么您的工作连接将很容易找到。
  • 使用SQL Server分析器和SQLProfiler TSQL_Replay模板来跟踪打开的连接。如果您熟悉Profiler,这个方法比使用sp_who进行轮询要简单。
  • 使用Performance Monitor监视池和连接。我马上会讨论这种方法。
  • 监视代码中的性能计数器。通过使用例程提取计数器或使用新的. net PerformanceCounter控件,可以监视连接池的运行状况和已建立的连接数量。

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

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

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

这主要是由于应用程序中没有关闭连接。使用“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时,我们到远程数据库的连接立即开始超时由于这个变化

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

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

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

似乎即使Disposeing连接时也会抛出异常。

您已经泄漏了代码上的连接。您可以尝试使用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.web>标签中添加

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

而且

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

 <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连接,你可以在两个连接字符串中更新“最大池大小”条目,按照下面的说明:

  1. 使用远程桌面登录到服务器
  2. 打开我的电脑(Windows - E),进入C:\inetpub\vhosts[domain]\httpdocs
  3. 双击网页。配置文件。如果文件结构被设置为隐藏扩展名,这可能只是被列为web。这将打开Visual Basic或类似的编辑器。
  4. 找到你的连接字符串,这些看起来类似于下面的例子:

    "add name="SiteSqlServer" connectionString="server=(本地);database=dbname;uid=dbuser;pwd=dbpassword;pooling=true;connection lifetime=120;max pool size=25;"" < / p >

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

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

请确保您为连接池设置了正确的设置。这是非常重要的,正如我在下面的文章中解释的那样: https://medium.com/@dewanwaqas/ configurs-that-- -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();
}

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

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

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

enter image description here

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

enter image description here

在“等待”中,对我自己的GetConnection方法的调用多达数千次。或“;Scheduled"状态。

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

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

[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.GetAllValuesForEmployee(d)进行数据库调用。

虽然这在性能方面是非常不好,但在异步上下环境中,它的行为方式是,它正在消耗连接池连接,而没有适当地释放它们。

解决方案

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

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

吸取的教训

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

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

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

没有连接泄漏,因为我只是部署alpha应用程序(没有真正的用户),我与活动监视器和sp_who确认,实际上没有连接到数据库。

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

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

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

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

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

=> 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语句一起

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

化简为

using var db = new MyDbContext();

var db = new MyDbContext();