我在连续运行的程序的连接池方面遇到了问题。当我在任务中对数据库进行大量查询(每 4 分钟 5 次(查询 3 个表并将结果保存到一个表))时,就会出现问题。
连接池超出了最大池连接大小。奇怪的是,对于特定的连接字符串/机器/用户条目,我有一百个
AWAITING COMMAND
条目。我的理解是 AWAITING COMMAND
意味着这个连接可以被重用,但是由于一些奇怪的未知原因,当从任务运行命令时,我无法重用可用的连接,它们只是等待任何人,并且在一段时间后出现错误,我已经已达到最大池连接大小。
到目前为止的假设:
从任务数据库运行命令时,将此解释为无效以重用可用连接
连接没有关闭,但为什么呢?似乎用 using 关键字关闭它们。更重要的是 DB 上有 100
AWAITING COMMAND
。
处理程序由于某种原因没有被垃圾收集?但 100 AC 表明了一些其他的东西。
当我尝试在本地 SQL Server Express 上复制此问题时,此问题发生在非常尴尬的情况下。我必须添加
Thread.Sleep(600000)
来模拟这种情况,最终我能够得到最大池错误。在这种情况下,所有连接都是打开的,因此它的含义相当不言自明。
在本地机器 -> 服务器数据库场景中,我不认为我可以一次打开 100 个连接;他们宁愿出于某种原因保持开放。当在本地计算机 -> 服务器数据库情况下启动此程序时,我什至不需要添加
Thread.Sleep(600000)
来使程序崩溃。
所有这些都是我根据观察做出的假设。我想不出在我的连续运行服务中是什么导致了这种情况,我每 4 分钟查询一次数据库。
在我进行完整的本地测试后,我很困惑
AWAITING COMMAND
是否意味着该连接可以重用?
我忘了提及,我的初始程序可以运行几天,然后我最终会遇到此最大池错误。
下面是可能产生此类问题的程序:
using System;
using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
namespace Pooling
{
class Program
{
private static int connectionIterations;
private static string connectionString = "Data Source=localhost;Initial Catalog=localDB;Integrated Security=True";
static void Main(string[] args)
{
try
{
Iterations();
while(true)
{
ConnectionSnowball();
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
private static void ConnectionSnowball()
{
Parallel.For(0, connectionIterations, i =>
{
try
{
Console.WriteLine($"Connection id: {i}");
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("SELECT 1 FROM test_table", connection);
connection.Open();
cmd.ExecuteNonQuery();
Thread.Sleep(600000);
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
});
}
private static void Iterations()
{
connectionIterations = 200;
}
}
}
我调试了你的代码,没有发现连接泄漏。您只是遇到了连接池溢出。我为你检查了两种可能的解决方案。
禁用池连接
private static string connectionString = "Data Source=localhost;Initial Catalog=localDB;Integrated Security=True;Pooling=False";
增加连接池
private static string connectionString = "Data Source=localhost;Initial Catalog=localDB;Integrated Security=True;Max Pool Size=200";
要测试在
ConnectionSnowball()
调用之前、期间和之后连接如何增加和减少,您可以使用此 SQL 查询
select count(1) from sys.dm_exec_sessions where database_id = DB_ID(N'localDB')
有关连接字符串参数的更多详细信息 SqlConnection.ConnectionString 属性
其他可能的解决方案是使用SQL 作业。对于此任务,这可能是一个更合适的解决方案,因为大量连接非常耗费资源。
由于您的代码中没有连接泄漏,您是否尝试过重新启动 IIS?