【问题标题】:How to optimize Postgresql max_connections and node-postgres connection pool?如何优化 Postgresql max_connections 和 node-postgres 连接池?
【发布时间】:2017-03-13 20:13:35
【问题描述】:

简而言之,我无法支持来自利用 Postgresql、Node.js 和 node-postgres 的数据 API 每分钟超过 5000 个读取请求。瓶颈似乎在 API 和 DB 之间。以下是实现细节。

我正在为 Node.js 驱动的数据 API 使用 AWS Postgresql RDS 数据库实例(m4.4xlarge - 64 GB 内存、16 个 vCPU、350 GB SSD、无预置 IOPS)。默认情况下,RDS 的 max_connections=5000。节点 API 在两个集群之间进行负载平衡,每个集群有 4 个进程(2 个 Ec2 和 4 个 vCPU,在集群模式下使用 PM2 运行 API)。我使用node-postgres 将API 绑定到Postgresql RDS,并尝试使用它的连接池功能。下面是我的连接池代码示例:

var pool = new Pool({
    user: settings.database.username,
    password: settings.database.password,
    host: settings.database.readServer,
    database: settings.database.database,
    max: 25, 
    idleTimeoutMillis: 1000
});

/* Example of pool usage */
pool.query('SELECT my_column FROM my_table', function(err, result){
    
    /* Callback code here */
});

使用此实现并使用负载测试器进行测试,我可以在一分钟内支持大约 5000 个请求,平均响应时间约为 190 毫秒(这是我所期望的)。一旦我每分钟发出超过 5000 个请求,我的响应时间在最好的情况下会增加到超过 1200 毫秒,在最坏的情况下,API 开始频繁超时。监控表明,对于运行 Node.js API 的 EC2,CPU 利用率仍低于 10%。因此,我的重点是 DB 和 API 与 DB 的绑定。

我已尝试增加(并减少)node-postgres“最大”连接设置,但 API 响应/超时行为没有变化。我也尝试过在 RDS 上配置 IOPS,但没有任何改进。另外,有趣的是,我将 RDS 扩展到 m4.10xlarge(160 GB 内存,40 个 vCPU),虽然 RDS CPU 使用率大幅下降,但 API 的整体性能大幅下降(甚至无法支持每分钟 5000 个请求我能够使用较小的 RDS)。

我在很多方面都处于不熟悉的领域,并且不确定如何最好地确定当每分钟超过 5000 个请求时,这些移动部件中的哪一个会成为 API 性能的瓶颈。如前所述,我根据对 Postgresql 配置文档和 node-postgres 文档的审查尝试了各种调整,但无济于事。

如果有人对如何诊断或优化有任何建议,我将不胜感激。

更新

在扩展到 m4.10xlarge 之后,我执行了一系列负载测试,改变了每个池中的请求/分钟数和最大连接数。以下是一些监控指标的屏幕截图:

【问题讨论】:

  • 最大连接默认为100。你试过增加它吗?

标签: node.js postgresql api aws-rds node-postgres


【解决方案1】:

为了支持超过 5k 的请求,同时保持相同的响应率,您需要更好的硬件...

简单的数学表明: 5000 requests*190ms avg = 950k ms divided into 16 cores ~ 60k ms per core 这基本上意味着您的系统负载很高。
(我猜你有一些空闲的 CPU,因为在网络上浪费了一些时间)

现在,您问题中真正有趣的部分来自扩展尝试:m4.10xlarge(160 GB 内存,40 个 vCPU)。
CPU 利用率下降表明纵向扩展释放了 DB 时间资源 - 所以您需要推送更多请求!
2 条建议:

  • 尝试将连接池增加到 max: 70 并查看网络流量(取决于您可能占用网络的数据量)
  • 另外,您是否从应用程序端向数据库异步请求?确保您的应用实际上可以推送更多请求。

【讨论】:

  • 非常感谢。我将尝试将“max”调整为 70,(Node.js API 在集群中复制了 8 次,这意味着有效最大值为 70*8 = 560)。关于来自应用程序的异步 DB 请求 - 我假设一切都是异步的,因为 Node.js 的异步功能和 node-postgres Postgres 客户端被其开发人员描述为“非阻塞”。但我必须承认,我没有仔细检查图书馆内部以确认这一点。
  • 你在数据库服务器上有监控吗? Io/网络 - 有什么飙升吗?只是想知道如果增加它会让你减少到 2k - 减少到 10 会改善吗?
  • 这里有来自max: 20 的 10xlarge 测试的详细信息:3000 次读取查询/分钟的负载测试。 CPU大约是7%。没有超时;以 4000 读取查询/分钟进行负载测试。 CPU 约为 64%。超过一半的应用程序请求超时。我会尝试一些监控屏幕抓取并更新帖子。
  • 我们知道 CPU 不是瓶颈——看看 io 和网络。没有超时意味着你可以推送更多:)
  • 根据您的建议,我对 m4.10xlarge 进行了一系列负载测试。我已经用似乎最敏感的数据库指标更新了原始问题。
【解决方案2】:

最好的方法是根据调用的优先级为每个 API 调用使用单独的Pool

const highPriority = new Pool({max: 20}); // for high-priority API calls
const lowPriority = new Pool({max: 5}); // for low-priority API calls

然后,您只需为每个 API 调用使用正确的池,以获得最佳的服务/连接可用性。

【讨论】:

    【解决方案3】:

    由于您对读取性能感兴趣,可以在两个(或多个)PostgreSQL 实例之间设置复制,然后使用pgpool II 来实现实例之间的负载平衡。

    水平扩展意味着如果您决定下周需要达到 10,000 个并发读取,您将不会开始达到 AWS 的最大实例大小。

    您也开始在您的架构中获得一些高可用性。

    --

    很多时候人们会使用pgbouncer 作为连接池,即使他们已经在他们的应用程序代码中内置了一个。 pgbouncer 工作得非常好,通常更容易配置和管理 pgpool,但它不做负载平衡。不过,我不确定它在这种情况下是否会对您有很大帮助。

    【讨论】:

    • 我确实考虑过只读副本,但我有兴趣了解有关复制滞后的更多信息。我们的应用程序的用户经常写入数据,然后以影响其读取请求有效负载内容的方式加以利用。因此,复制滞后可能会在我们的解决方案中引入其他延迟。有没有办法估计复制延迟?
    • 这里有一篇关于 postgresql 列表中的复制滞后测量的讨论:postgresql.org/message-id/…
    • 根据我的经验,它通常不会太糟糕。当页面呈现并且最终用户进行查询时,复制已被赶上。您遇到问题的地方是当您立即发送写入然后读取时。我认为 pgpool 中的一些设置在这些情况下会有所帮助,尽管我已经好几年没有弄乱 pgpool 设置了。
    猜你喜欢
    • 1970-01-01
    • 2017-01-03
    • 2013-12-08
    • 2021-07-13
    • 1970-01-01
    • 2012-04-30
    • 2014-12-15
    • 1970-01-01
    • 2014-07-07
    相关资源
    最近更新 更多