我正在尝试加载测试一个基本的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 服务器本身中缺少某些内容吗?还是在连接上?
需要指出的是,这些是霰弹枪呼叫。因此,批处理会尽快触发,然后等待每个请求返回。
这也是使用 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);
}
另一个注意事项
不开枪(等待上一个调用完成,然后再发送另一个调用(似乎具有足够不错的吞吐量。这似乎是同时处理太多请求的问题
版本信息dotnet2.1.401
SqlClient4.5.1
我可以验证正在发生一些可疑的事情,但它可能没有汇集。我创建了一个控制台应用程序,并在同一本机上从 Windows 控制台和 WSL 控制台运行它。这样,我就可以从相同的客户端运行相同的代码,但操作系统/运行时不同。
在 Windows 上,即使使用荒谬的 500 DOP ,每个连接也花费不到一毫秒的时间:
985 : 00:00:00.0002307
969 : 00:00:00.0002107
987 : 00:00:00.0002270
989 : 00:00:00.0002392
WSL 中的相同代码将需要 8 秒或更长时间,即使 DOP 为 20!较大的 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);
}
}