低负载(dotnet核心)下与数据库的连接问题

时间:2018-09-07 08:07:11

标签: c# sql-server linux .net-core

我正在尝试对基本API进行负载测试,我开始从数据库连接中遇到一些奇怪的问题。 现在,我将其范围缩小到SQL连接本身。 (我使用SELECT 1仅测试连接)

在非常低的负载(每秒15个呼叫)下,一切都按预期工作。

在低负载(每秒25个呼叫)下,前4-5个呼叫以正常的速度返回,然后迅速降低。由于池中没有连接,导致大量呼叫超时。

在中等负载(每秒50个呼叫)下,所有内容完全锁定,没有任何结果。而且我开始收到诸如A network-related or instance-specific error occurred while establishing a connection to SQL Server.之类的奇怪信息。无法再次从池中获得连接。

服务器上的

exec sp_who2也不显示来自dotnet的连接。

更糟糕的是,从中恢复的唯一方法就是弹跳整个服务。

我已经排除了服务器本身,因为这发生在功能强大的本地SQL服务器,azureSql数据库以及在docker上运行的本地服务上。

 int selected = 0;
 var timer = Stopwatch.StartNew();
 using (SqlConnection connection = CreateNewConnection())
 {
      try
      {
          connection.Open();
          selected = connection.QueryFirst<int>("SELECT 1");
          timer.Stop();
      }
      catch (Exception e)
      {
          Console.WriteLine("Failed connection");
          Console.WriteLine("fatal    " + e.Message);
          responseBuilder.AddErrors(e);
      }
      finally
      {
          connection.Close();
      }
 }

 responseBuilder.WithResult(new {selected, ms = timer.ElapsedMilliseconds});

我什至尝试进行处理,并强制手动关闭连接以了解发生的情况。

这正在运行dotnet核心和dapper(即使没有dapper,我也会遇到相同的问题)

我还尝试将最大连接池限制提高到1000之类的荒谬数字,但没有效果。

修改

尝试了更多之后,我决定尝试使用Postgres。完美地以每秒超过1k的呼叫速度运行。 我在sql server本身上缺少什么吗?还是在连接上?

需要指出的是,这些是散弹枪。因此,批次会尽快解雇,然后等待每个请求返回。

这也正在使用linux(环境是docker k8s)

有人想知道如何建立连接

    private IDbConnection CreateNewConnection()
    {
        var builder = new SqlConnectionStringBuilder()
        {
            UserID = "sa",
            Password = "012Password!",
            InitialCatalog = "test",
            DataSource = "localhost",
            MultipleActiveResultSets = true,
            MaxPoolSize = 1000
        };
        return new SqlConnection(builder.ConnectionString);
    }

另一个笔记

未完成任务(等待上一个调用完成,然后再发送另一个)似乎具有足够的吞吐量。似乎同时处理了太多请求

版本信息 dotnet 2.1.401 SqlClient 4.5.1

1 个答案:

答案 0 :(得分:3)

我可以验证发生了什么可疑现象,但可能不是池中现象。我创建了一个控制台应用程序,并从Windows控制台和WSL控制台在同一框中运行它。这样,我可以从相同的客户端但在不同的OS /运行时上运行相同的代码。

在Windows上,即使使用了荒谬的500 DOP,每个连接也花费了不到一毫秒的时间:

985 : 00:00:00.0002307
969 : 00:00:00.0002107
987 : 00:00:00.0002270
989 : 00:00:00.0002392

即使在DOP为20的情况下,WSL中的相同代码也将花费8秒或更长时间! DOP值较大会导致超时。 10将产生类似于Windows的结果。

我一度禁用MARS,但性能恢复正常:

983 : 00:00:00.0083687
985 : 00:00:00.0083759
987 : 00:00:00.0083971
989 : 00:00:00.0083938
992 : 00:00:00.0084922
991 : 00:00:00.0045206
994 : 00:00:00.0044566

这仍然比直接在Windows上运行要慢20倍,但是直到您并排检查数字时才注意到。

这是我在两种情况下使用的代码:

   static void Main(string[] args)
    {
        Console.WriteLine("Starting");

        var options=new ParallelOptions { MaxDegreeOfParallelism = 500 };
        var watch=Stopwatch.StartNew();
        Parallel.For(0,1000,options,Call);
        Console.WriteLine($"Finished in {watch.Elapsed}");
    }

    public static void Call(int i)
    {            
        var watch = Stopwatch.StartNew();

        using (SqlConnection connection = CreateNewConnection())
        {
            try
            {
                connection.Open();
                var cmd=new SqlCommand($"SELECT {i}",connection);
                var selected =cmd.ExecuteScalar();                    
                Console.WriteLine($"{selected} : {watch.Elapsed}");
            }
            catch (Exception e)
            {
                Console.WriteLine($"Ooops!: {e}");
            }
        }
    }

    private static SqlConnection CreateNewConnection()
    {
        var builder = new SqlConnectionStringBuilder()
        {
            UserID = "someUser",
            Password = "somPassword",                        
            InitialCatalog = "tempdb",
            DataSource = @"localhost",
            MultipleActiveResultSets = true,
            Pooling=true //true by default                
            //MaxPoolSize is 100 by default
        };
        return new SqlConnection(builder.ConnectionString);
    }
}