连续运行的应用程序

时间:2017-11-23 15:51:11

标签: c# sql-server multithreading connection-pooling

我在连续运行程序时遇到连接问题。当我执行大量查询(每4分钟5次(查询3个表并将结果保存到一个))到任务中的数据库时,会出现问题。连接池用尽最大池连接大小。关于这个奇怪的事情,我在DB 100的特定连接字符串/机器/用户条目的AWAITING COMMAND条目。我的理解是,AWAITING COMMAND意味着这个连接可以被重用,但是从一些奇怪的未知原因来看,当我从Tasks运行命令时,它不能重复使用可用的连接而且它们只是等待没有人,并且在一段时间后出现错误,我就会发现错误。已达到最大池连接大小。

到目前为止的假设:

  1. 从任务DB运行命令时,将其解释为无效以重用可用连接

  2. 连接尚未结束,但为什么?似乎用关键字关闭它们。更重要的是100个AWAITING COMMANDS一个DB。

  3. 处理程序因某些原因无法收集垃圾?但100 AC告诉别人。

  4. 更新: LOCALDB观察/摘要:

    当我试图在本地数据库SQL Server Express上复制此问题时,这个问题在非常尴尬的情况下发生。我不得不添加Thread.Sleep(600000)以模拟情况。最后,我得到了最大池错误,但在这种情况下,所有连接都是开放的,所以它相当自我解释。

    在本地 - >服务器方案,我不这么认为我可以一次打开100个连接,他们宁愿保持开放由于某种原因。在localMachine上启动此程序时 - > serverDB情况我甚至不需要添加Thread.Sleep(600000)来崩溃程序。

    所有这些都是我根据观察得出的假设。在我的连续运行服务中,每4分钟查询一次数据库,我无法想到这个问题。

    PS。完成本地测试后,如果COMMAND AWAITING意味着可以重用此连接,我会感到困惑吗?

    更新2 忘记提及我的初始程序可能会在我最终遇到此最大池错误之前运行几天。

    以下是可以产生此类问题的程序:

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

1 个答案:

答案 0 :(得分:0)

我调试了你的代码,发现没有连接泄漏。你只是有一个连接池溢出。我为您检查了两种可能的解决方案。

禁用合并连接

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 Property

其他可能的解决方案是使用SQL jobs。对于此任务,这可能是一个更合适的解决方案,因为大量连接是非常耗费资源的。