我正在尝试对基本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
答案 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);
}
}