PostgresSQL 9.6
数据库。这两台服务器只做一件事,每5秒钟向Postgres db发送一个SELECT 1
查询。
连接到db并获取数据的典型时间:
- Node:
25 MS
- .NET Core 3.1使用Npsql 4.1.1(我也尝试了4.1.2,没有区别):
500 MS
我的问题是,我的.NET Core应用程序在获取数据方面比Node慢20倍。我认为由于某些原因.NET Core未对连接进行池化。无论是在本地运行应用程序还是在Azure App Services上运行应用程序时,都会出现这种缓慢现象,没有任何区别。 我想解决.NET --> Postgres的速度慢的问题。
请仅浏览相关细节,不要阅读此点之后的全部内容 - 我认为只有.NET Core
代码相关。
从我的机器(其中运行了Node和.NET Core应用程序)到数据库的PsPing
:
Connecting to foobarPostGres:5432 (warmup): from someIp: 19.98ms
Connecting to foobarPostGres:5432: from someIp: 1.65ms
Connecting to foobarPostGres:5432 from someIp: 1.18ms
Connecting to foobarPostGres:5432: from someIp: 1.23ms
Connecting to foobarPostGres:5432: from someIp: 1.06ms
为了完整起见,NODE
的示例如下所示(请注意,它建立连接的第一次也比较慢):
Attempting to establish a connection...
Elapsed ms: 644.1334999799728
RESP: { '?column?': 1 }
Elapsed ms: 22.76109904050827
RESP: { '?column?': 1 }
Elapsed ms: 21.984400033950806
RESP: { '?column?': 1 }
Elapsed ms: 26.043799996376038
RESP: { '?column?': 1 }
Elapsed ms: 22.538798987865448
RESP: { '?column?': 1 }
.NET Core
的连接时间如下:
5:13:32 PM: SLOW QUERY, CONN TIME: 4153, QUERY TIME: 18
5:13:53 PM: SLOW QUERY, CONN TIME: 707, QUERY TIME: 17
5:14:14 PM: SLOW QUERY, CONN TIME: 589, QUERY TIME: 16
5:14:35 PM: SLOW QUERY, CONN TIME: 663, QUERY TIME: 18
5:14:56 PM: SLOW QUERY, CONN TIME: 705, QUERY TIME: 16
请注意,初始连接时间非常缓慢,后续请求建立连接的时间也很长。
无论如何,由于我非常着急,现在我将发布所有代码,并进行解释。连接字符串看起来像这样:
public static string CONNECTION_STRING {
get {
return $"Server={HOST}; User Id={USER}; Database={DB_NAME}; Port={PORT}; Password={PWD}; SSLMode=Prefer";
}
}
据我了解,如果使用这个连接字符串,我应该可以直接获取到连接池。请注意,我已经尝试关闭SSL
并删除相关行,但这并没有起到帮助作用。
我的健康检查控制器如下:
// GET api/health/getdbhealthselectone
[HttpGet]
[Route("getdbhealthselectone")]
public async Task<IActionResult> GetDbHealthSelectOne()
{
int testData = await _healthCheckRepo.RunHealthCheckSelectOne();
return Ok(testData);
}
我的健康检查仓库方法看起来像这样:
public async Task<int> RunHealthCheckSelectOne()
{
await using var conn = new NpgsqlConnection(AzureDbConnectionInfo.CONNECTION_STRING);
var connTimer = System.Diagnostics.Stopwatch.StartNew(); // TODO: Remove this testing line
await conn.OpenAsync();
connTimer.Stop(); // TODO: Remove this testing line
var msToConnect = connTimer.ElapsedMilliseconds; // TODO: Remove this testing line
int testData = 999;
var jobsQueryTimer = System.Diagnostics.Stopwatch.StartNew(); // TODO: Remove this testing line0
await using (var cmd = new NpgsqlCommand("SELECT 1", conn))
await using (var reader = await cmd.ExecuteReaderAsync())
while (await reader.ReadAsync()) {
testData = reader.GetInt32(0);
};
jobsQueryTimer.Stop(); // TODO: Remove this testing line
var msToQuery = jobsQueryTimer.ElapsedMilliseconds; // TODO: Remove this testing line
LogQueryIfSlow(msToConnect, msToQuery, _logger); // TODO: Remove this testing line
return testData;
}
请注意这里的计时器 -
await conn.OpenAsync();
是远远占用大多数时间的部分,查询本身很快。另外,为了节省时间 - 我以前曾经运行过这段代码,没有使用 async
,没有任何区别。最后,如果有依赖注入问题,仓储库在一个类库中,API 项目引用它,并且:
services.AddSingleton<IHealthCheckRepository, HealthCheckRepository>();
这就是它看到的方式。我相信这是所有相关信息 - 我一直在与 Azure 支持团队通话,他们没有发现数据库配置方面的任何问题。.NET Core 应用程序非常轻巧,所以不像它已经超载了,而且正在测试中,除了我的测试之外没有任何流量。
额外信息:为了完整起见,这里是我的整个 Node.js 应用程序,它连接到数据库并发布了性能结果(去掉了 conn 数据)。
const { Pool, Client } = require('pg');
const { performance } = require('perf_hooks');
const pool = new Pool({
user: 'SECRET',
host: 'SECRET',
database: 'SECRET',
password: 'SECRET',
port: 5432,
})
function runQuery(pool) {
var t0 = performance.now();
pool.query('SELECT 1', (err, res) => {
if (err) {
console.log('ERROR: ', err.stack)
} else {
console.log('RESP: ', res.rows[0])
}
var t1 = performance.now();
console.log('Elapsed ms: ', t1-t0);
//pool.end()
});
}
setInterval(() => {runQuery(pool)}, 5000);
编辑:为了后人,以下是修复连接池超时后的.NET Core时间 - 它比node.js快,除了初始连接需要一段时间外,但我还没有检查一些默认值:
CONN: 1710 QUERY: 18
CONN: 0 QUERY: 16
CONN: 0 QUERY: 16
CONN: 0 QUERY: 17
CONN: 0 QUERY: 16
CONN: 0 QUERY: 23
CONN: 0 QUERY: 16
CONN: 0 QUERY: 16
CONN: 0 QUERY: 23
CONN: 0 QUERY: 16
CONN: 0 QUERY: 16
Minimum Pool Size=5
。我不明白为什么它在300秒之前关闭了池中的连接,但它确实这样做了。这使我的连接时间为0,没有间歇性问题。请写出答案,以便我可以授予您赏金。如果您想在此处解释文档中的池化部分https://www.npgsql.org/doc/connection-string-parameters.html,那就太好了,或者只需回答说“min pool size”=)再次感谢,虽然很小,但如果没有您,我就无法解决它。 - VSO