【发布时间】:2019-02-12 13:06:24
【问题描述】:
我正在尝试对一个基本 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 core 和 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);
}
另一个说明
Not shotgunning(等待上一个调用完成,然后再发送另一个)似乎有足够的吞吐量。这似乎是同时处理太多请求的问题
版本信息
点网2.1.401
SqlClient4.5.1
【问题讨论】:
-
有一点需要指出,这些是猎枪式的呼叫。因此,批处理会尽快启动,然后等待每个请求返回。
-
似乎 DBContext 是为调用而创建的,并且在整个会话中都保持不变。您能否显示您知道如何连接数据库的代码以及要连接的服务器以及每次调用都会持久化或实例化的代码
-
@StevenDall 更新问题,不要添加 cmets。至于遗漏什么,我想说您没有提供所有代码,但看起来
CreateConnection正在泄漏连接。使用了连接池,因此您不需要重新打开与服务器的真实连接。当您调用Close()或退出using块时,连接被重置并放回池中。如果连接实际上已关闭,您不会收到这样的池错误。 PS:这里不需要.Close(),它会在执行离开using块时被调用。 -
@StevenDall 您没有提及您使用的操作系统或 .NET Core 版本。 Linux 的 SqlClient 库中可能存在错误。另一方面,连接池并不是新事物,当您考虑重用 same 连接时,每秒 25 次调用非常低。除非连接字符串禁用连接池?
-
有一个Github issue about a connection pooling bug 影响了所有操作系统,并已在 SqlClient 4.5.0 中修复。也许这是一个回归,或者一个新的错误?讨论表明问题是由ThreadPool 的不当使用引起的。驱动程序在没有实际打开连接的情况下被卡住,这可以解释为什么您在服务器端看不到任何连接。您可能应该创建一个最小程序并尝试在 Windows 中使用它。
标签: c# sql-server linux .net-core