连续运行应用程序上的 SQL Server 连接池

问题描述 投票:0回答:2

我在连续运行的程序的连接池方面遇到了问题。当我在任务中对数据库进行大量查询(每 4 分钟 5 次(查询 3 个表并将结果保存到一个表))时,就会出现问题。

连接池超出了最大池连接大小。奇怪的是,对于特定的连接字符串/机器/用户条目,我有一百个

AWAITING COMMAND
条目。我的理解是
AWAITING COMMAND
意味着这个连接可以被重用,但是由于一些奇怪的未知原因,当从任务运行命令时,我无法重用可用的连接,它们只是等待任何人,并且在一段时间后出现错误,我已经已达到最大池连接大小。

到目前为止的假设:

  1. 从任务数据库运行命令时,将此解释为无效以重用可用连接

  2. 连接没有关闭,但为什么呢?似乎用 using 关键字关闭它们。更重要的是 DB 上有 100

    AWAITING COMMAND

  3. 处理程序由于某种原因没有被垃圾收集?但 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;
        }
    }
}
c# sql-server multithreading connection-pooling
2个回答
1
投票

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

禁用池连接

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 作业。对于此任务,这可能是一个更合适的解决方案,因为大量连接非常耗费资源。


0
投票

由于您的代码中没有连接泄漏,您是否尝试过重新启动 IIS?

© www.soinside.com 2019 - 2024. All rights reserved.