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

10
简而言之,我在使用Postgresql、Node.js和node-postgres的数据API时,遇到了一个问题,即每分钟支持超过5000个读请求的困难。瓶颈似乎出现在API和数据库之间。以下是实现细节。
我正在使用AWS的Postgresql RDS数据库实例(m4.4xlarge-64 GB内存,16个虚拟CPU,350 GB SSD,没有预留的IOPS)作为Node.js驱动的数据API。默认情况下,RDS的max_connections=5000。Node API在两个集群中进行负载均衡,每个集群有4个进程(2个具有4个虚拟CPU的Ec2实例,在集群模式下使用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%以下。因此,我的重点是数据库和API与数据库的绑定。
我尝试增加(或减少)node-postgres的“max”连接设置,但API的响应/超时行为没有改变。我还尝试了在RDS上使用预配置的IOPS,但没有改善。有趣的是,我将RDS扩展到m4.10xlarge(160 GB内存,40个虚拟CPU),虽然RDS的CPU利用率大大降低,但API的整体性能却明显恶化(甚至无法支持我之前能够使用较小的RDS支持的每分钟5000个请求)。
我在很多方面都处于陌生的领域,对于如何确定在每分钟超过5000个请求时,哪个部分是限制API性能的瓶颈感到不确定。如前所述,我已经根据Postgresql配置文档和node-postgres文档的审查尝试了各种调整,但都没有成功。
如果有人对如何诊断或优化有建议,我将非常感激。
更新:
在升级到m4.10xlarge后,我进行了一系列的负载测试,变化了每分钟请求的数量和每个连接池的最大连接数。这里是一些监控指标的屏幕截图。

monitoring metrics

db connections


最大连接默认为100。你尝试增加过它吗? - Andrew Scott Evans
3个回答

7
为了支持超过5k个请求,同时保持相同的响应速度,您需要更好的硬件设备... 简单的数学公式如下: 5000个请求*平均190毫秒=950k毫秒分配到16个核心~每个核心60k毫秒 这基本上意味着您的系统负载很高。(我猜您有一些CPU空闲时间浪费在网络上) 现在,您问题中真正有趣的部分来自于扩展尝试:m4.10xlarge(160 GB内存,40个vCPUs)。 CPU利用率的下降表明,扩展释放了DB时间资源-因此您需要推送更多的请求! 2个建议:
  • 尝试将连接池增加到max: 70并查看网络流量(根据数据量的大小,您可能会占用网络)
  • 另外,您的对DB的请求是否从应用程序端异步处理?确保您的应用程序实际上可以推送更多的请求。

  • 非常感谢。我将尝试将“max”调整为70(在集群中复制了8次Node.js API,这意味着有效的最大值为70 * 8 = 560)。关于应用程序的异步DB请求-鉴于Node.js的异步特性和[node-postgres](https://github.com/brianc/node-postgres) Postgres客户端被其开发人员描述为“非阻塞”,我假设一切都是异步的。但我必须承认,我还没有仔细检查库内部以确认。 - rgwozdz
    你的数据库服务器有监控吗?输入/输出或网络 - 有什么异常波动吗?还想知道如果增加它会使您降至2k - 减少到10是否会改善情况? - cohenjo
    以下是使用 max: 20 进行的10xlarge测试的详细信息:每分钟3000个读取查询的负载测试。CPU占用率约为7%。没有超时;每分钟4000个读取查询的负载测试。CPU占用率约为64%。超过一半的应用程序请求超时。我将尝试获取一些监控屏幕截图并更新帖子。 - rgwozdz
    我们知道 CPU 不是瓶颈 - 看看 IO 和网络。没有超时意味着你可以推送更多 :) - cohenjo
    根据您的建议,我对m4.10xlarge进行了一系列负载测试。我已经更新了原始问题,并提供了最具响应性的数据库指标。 - rgwozdz
    嗨,你应用程序配置中的某些内容出了问题 - 无论是max=10还是max=70,你只有80个db连接。顺便问一下,在测试期间你的应用程序CPU如何 - 这8个vCPU是否能处理所有请求? - cohenjo

    4
    最好的方法是根据调用的优先级为每个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调用使用正确的池,以获得最佳的服务/连接可用性。

    0

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

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

    您还可以在架构中获得一些高可用性。

    --

    很多时候,即使应用程序代码中已经有连接池器,人们仍会使用pgbouncer作为连接池器。pgbouncer的工作效果非常好,通常比pgpool更容易配置和管理,但它不进行负载均衡。虽然在这种情况下我不确定它是否会对您有所帮助。

    我肯定考虑过读取副本,但对于复制延迟更感兴趣。我们的应用程序有用户经常写入数据,然后以影响其读取请求有效负载内容的方式利用该数据。因此,复制延迟可能会向我们的解决方案引入其他延迟。有没有一种方法可以估计复制延迟? - rgwozdz
    在postgresql列表中有一篇关于复制延迟测量的讨论,链接如下:https://www.postgresql.org/message-id/CADKbJJWz9M0swPT3oqe8f9+tfD4-F54uE6Xtkh4nERpVsQnjnw@mail.gmail.com - rotten
    根据我的经验,通常情况下并不会太糟糕。当页面呈现和最终用户进行查询时,复制已跟上。问题出现在您发送写入后立即进行读取的情况下。我认为在这些情况下,pgpool中有一些设置可以帮助,尽管我已经好几年没有涉及pgpool的设置了。 - rotten

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接