如何优化 Postgresql max_connections 和 node-postgres 连接池?

Posted

技术标签:

【中文标题】如何优化 Postgresql max_connections 和 node-postgres 连接池?【英文标题】:How to optimize Postgresql max_connections and node-postgres connection pool? 【发布时间】: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。你试过增加它吗? 【参考方案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 设置了。

以上是关于如何优化 Postgresql max_connections 和 node-postgres 连接池?的主要内容,如果未能解决你的问题,请参考以下文章

09 nginx 中 upstream max_conns 配置为 1, 导致的一部分静态资源请求成功, 一部分静态资源请求失败

09 nginx 中 upstream max_conns 配置为 1, 导致的一部分静态资源请求成功, 一部分静态资源请求失败

09 nginx 中 upstream max_conns 配置为 1, 导致的一部分静态资源请求成功, 一部分静态资源请求失败

如何优化 PostgreSQL COUNT GROUP BY 查询?

如何优化大表的 Postgresql ARRAY_AGG 查询?

PostgreSQL数据库导入大量数据时如何优化