簡體   English   中英

在連接到 Postgres 方面,Node 比 .NET Core 快 20 倍

[英]Node is 20x faster Than .NET Core in Connecting to Postgres

我有兩台服務器連接到 Azure 上托管的PostgresSQL 9.6數據庫。 服務器正在做一件事 - 每 5 秒用SELECT 1查詢訪問 Postgres 數據庫。

連接到數據庫並獲取數據的典型時間:

  • 節點: 25 MS
  • .NET Core 3.1 使用 Npsql 4.1.1(我也嘗試過 4.1.2,沒有差異): 500 MS

我的問題是我的 .NET Core 應用程序在獲取數據方面比 Node慢 20 倍 相信.NET Core 由於某種原因沒有匯集連接。 這種緩慢發生在本地運行應用程序和在 Azure 應用程序服務上運行它時 - 沒有區別。 我想解決 .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 支持電話,他們沒有發現 db 配置問題。 .NET Core 應用程序是超輕量級的,所以它不會超載並且正在測試中,所以除了我的測試之外沒有流量。

額外:為了完整起見,這是我的整個節點應用程序,它訪問數據庫並發布性能(取出 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 中的時間 - 它比節點快,除了初始連接,這似乎需要一段時間,但我沒有檢查一些默認值:

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

您需要設置最小池大小。 這樣做可確保無論池使用情況如何,此數量的連接都對數據庫保持打開狀態。

默認情況下(至少對於NPGSQL ),最小大小為 0,因此如果連接有一段時間沒有使用,它將被關閉。

在您的測試中,您每 5 秒執行一次調用,這並不多,並且池可能會決定關閉未使用的連接。 根據文檔,它應該保持打開狀態 300 秒,而不僅僅是 15

第一個調用幾乎比其他調用長 5 秒。 對我來說,這看起來像是 IP 地址解析問題。 它首先選擇對給定服務器有缺陷的方法,然后在 5 秒后超時並選擇另一個有效的方法。 然后它會被緩存一段時間,這樣會繼續正常工作,直到緩存的條目過期。

要查看這是否是問題,請將數據庫主機的 IP 地址硬編碼到“主機”文件中,然后查看是否可以解決問題。 如果是這樣,那么根本原因就成為您的網絡工程師的問題。

在數據庫方面,您可以打開慢查詢日志記錄, log_min_duration_statement或更好的auto_explain.log_min_duration 但如果我的理論是正確的,這將不會顯示任何內容。 數據庫不知道您嘗試查找其 IP 地址花了多長時間。

有可能第一次查詢需要將大量數據從磁盤帶到內存,隨后的執行發現共享緩沖區中已經存在的所有內容。 你可以通過運行知道這一點

EXPLAIN (ANALYZE, BUFFERS) <your query>

“讀取”和“命中”的數量將告訴您從磁盤讀取了多少,以及在 RAM 中命中了多少。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM