Postgresql 和 .Net - 具有多个端点的连接池

Postgresql and .Net - Connection Pooling with Multiple Endpoints

基本介绍:

连接字符串:Host=IP;Port=somePort;Username=someUser;Password=somePass;Database=someDb;Maximum Pool Size=100

我的 Web 应用程序有几十个可通过 WS 和 HTTP 访问的端点。这些端点中的每一个都打开一个新的 NPGSQL 连接(都使用与上面相同的连接字符串),处理数据,然后通过 using 语句关闭。

问题: 当应用程序重新启动以进行更新时,通常会有 2-3,000 个用户全部重新连接。这通常会导致有关连接池已满的错误,并且由于已经有太多客户端而导致新连接被拒绝。但是,一旦它最终可以上线,它通常在任何给定时间只使用 5-10 个连接。

问题: 下面的逻辑是使用连接池的正确方法吗?每个端点使用指定连接池 100 的相同连接字符串创建新的 NPGSQL 连接?

似乎连接池经常激增到 100,但其中约 80/100 个连接在数据库查看器中显示为空闲,新连接请求由于池溢出而被拒绝。

更好的选择? 我也可以通过慢慢地允许新用户重新连接来尝试强制更“优雅”的启动,但我不确定与每个端点创建新连接的逻辑是否正确。

// DB Connection String - Used for all NPGSQL connections
const string connectionStr "Host=IP;Port=somePort;Username=someUser;Password=somePass;Database=someDb;Maximum Pool Size=100";

// Endpoint 1 available via Websocket
public async Task someRequest(someClass someArg)
{
    /* Create a new SQL connection for this user's request using the same global connections string */
    using var conn = new NpgsqlConnection(connectionStr);
    conn.Open();

    /* Call functions and pass this SQL connection for any queries to process this user request */
    somefunction(conn, someArg);
    anotherFunction(conn, someArg);

    /* Request processing is done */
    /* conn is closed automatically by the "using" statement above */
}

// Endpoint 2 available via Websocket
public async Task someOtherRequest(someClass someArg)
{
    /* Create a new SQL connection for this user's request using the same global connections string */
    using var conn = new NpgsqlConnection(connectionStr);
    conn.Open();

    /* Call functions and pass this SQL connection for any queries to process this user request */
    somefunction(conn, someArg);
    anotherFunction(conn, someArg);

    /* Request processing is done */
    /* conn is closed automatically by the "using" statement above */
}

// endpoint3();
// endpoint4();
// endpoint5();
// endpoint6();
// etc.

编辑: 我通过关闭连接并在处理期间将它们发送回池来进行建议的更改。但是,问题在启动时仍然存在。

  1. 应用程序启动 - 100 个连接声明用于池化。几乎所有人都处于闲置状态。应用程序收到连接池耗尽错误,甚至几乎没有交易被处理。

  2. 交易突然开始混乱,不知道为什么?这可能是在某种超时之后?我知道在某处的文档中有某种 300 秒的默认超时...这可能与这里匹配。

  3. 事务再次锁定,池耗尽错误恢复。

  4. 交易高峰和恢复,用户请求再次开始。

  5. 应用程序恢复正常。

编辑 2: 这个启动问题似乎一直需要 5 分钟从启动到清除空闲事务的死锁并开始 运行ning 所有查询。

我知道 5 分钟是 idle_in_transaction_session_timeout 的默认值。不过这次启动的时候试了运行ning SET SESSION idle_in_transaction_session_timeout = '30s';10s,好像一点影响都没有。

我不确定为什么这 100 个合并的连接会像启动时那样卡在空闲状态,需要 5 分钟才能清除并允许查询 运行 如果是这样...

一旦您在代码中关闭连接,连接就会释放到池中。根据您所写的内容,您在请求的整个时间内都将其保持打开状态,因此基本上 1 个用户 = 1 个连接和池仅用作等候室(timeout 设置,默认为 15 秒)。 Open/Close 每次需要访问数据库时的连接,因此连接返回到池中,当时间花在 .net 代码上时,可以由另一个用户使用。

示例,在伪代码中:

Enter function  
 Do some computations in .net, like input validation

  Open connection (grab it from the pool)
    Fetch info#1  
  Close connection (return it to the pool)

 Do some computations in .net, like ordering the result, computing an age from a date etc 
  
  Open connection (grab it from the pool)
    Fetch info #2   
  Close connection (return it to the pool)

 Do some computations in .net

Return

我忘记用一些最新信息更新此 post。我在代码中进行了一些其他内部优化。

其中一个主要问题,就是将 conn.Open(); 更改为 await conn.OpenAsync();,将 conn.Close(); 更改为 conn.CloseAsync();

我拥有的所有其他东西都是正确异步的,但 NPGSQL 中的所有新连接仍然存在 IO 阻塞,导致性能较差,并且出现大量突发。

一个非常明显的变化,但我什至没有想过为连接的打开和关闭寻找一个异步方法。