如何优化Postgresql max_connections 和node-postgres 连接池?
How to optimize Postgresql max_connections and node-postgres connection pool?
简而言之,我在利用 Postgresql、Node.js 和 node-postgres 支持数据 API 每分钟超过 5000 个读取请求时遇到问题。瓶颈似乎在 API 和数据库之间。以下是实施细节。
我正在使用 AWS Postgresql RDS 数据库实例(m4.4xlarge - 64 GB 内存,16 vCPUs,350 GB SSD,没有配置的 IOPS)用于 Node.js 供电数据API。默认情况下 RDS 的 max_connections=5000。节点 API 在两个集群之间进行负载平衡,每个集群有 4 个进程(2 个 Ec2s 和 4 vCPUs 运行 API with PM2 in cluster-mode)。我使用 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 开始频繁超时。监控表明,对于 EC2 运行,Node.js API、CPU 利用率仍然低于 10%。因此,我的重点是数据库和 API 与数据库的绑定。
我试图增加(并为此减少)node-postgres“最大”连接设置,但 API response/timeout 行为没有变化。我也试过在 RDS 上配置 IOPS,但没有改善。另外,有趣的是,我将 RDS 扩展到 m4.10xlarge(160 GB 内存,40 vCPUs),虽然 RDS CPU 利用率大幅下降,但 API 严重恶化(甚至无法支持我使用较小的 RDS 能够达到的每分钟 5000 个请求)。
我在很多方面都不熟悉,并且不确定在每分钟超过 5000 个请求时如何最好地确定这些移动部件中的哪些是瓶颈 API 性能。如前所述,我已尝试根据对 Postgresql 配置文档和 node-postgres 文档的审查进行各种调整,但无济于事。
如果有人对如何诊断或优化有任何建议,我将不胜感激。
更新
扩展到 m4.10xlarge 后,我执行了一系列负载测试,改变 request/min 的数量和每个池中的最大连接数.以下是监控指标的一些屏幕截图:
为了支持超过 5k 的请求,同时保持相同的响应率,您需要更好的硬件...
简单的数学表明:
5000 requests*190ms avg = 950k ms divided into 16 cores ~ 60k ms per core
这基本上意味着您的系统负载很高。
(我猜你有一些空闲 CPU 因为网络浪费了一些时间)
现在,您问题中真正有趣的部分来自放大尝试:m4.10xlarge(160 GB 内存,40 vCPUs)。
CPU 利用率的下降表明扩展释放了数据库时间资源 - 因此您需要推送更多请求!
2 条建议:
- 尝试将连接池增加到
max: 70
并查看网络流量(取决于您可能占用网络的数据量)
- 另外,您对数据库的请求是从应用程序端异步请求的吗?确保您的应用实际上可以推送更多请求。
如果你对读性能感兴趣可以在两个(或多个)PostgreSQL实例之间设置复制,然后使用pgpool II在实例之间进行负载平衡。
水平扩展意味着如果您决定下周需要进行 10,000 次并发读取,您将不会开始达到 AWS 的最大实例大小。
您也开始在架构中获得一些高可用性。
--
很多时候人们会使用 pgbouncer 作为连接池,即使他们已经在他们的应用程序代码中内置了一个。 pgbouncer 工作得很好,通常更容易配置和管理 pgpool,但它不做负载平衡。不过,我不确定在这种情况下它是否对您有很大帮助。
最好的方法是根据调用的优先级为每个 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 调用使用正确的池,以获得最佳 service/connection 可用性。
简而言之,我在利用 Postgresql、Node.js 和 node-postgres 支持数据 API 每分钟超过 5000 个读取请求时遇到问题。瓶颈似乎在 API 和数据库之间。以下是实施细节。
我正在使用 AWS Postgresql RDS 数据库实例(m4.4xlarge - 64 GB 内存,16 vCPUs,350 GB SSD,没有配置的 IOPS)用于 Node.js 供电数据API。默认情况下 RDS 的 max_connections=5000。节点 API 在两个集群之间进行负载平衡,每个集群有 4 个进程(2 个 Ec2s 和 4 vCPUs 运行 API with PM2 in cluster-mode)。我使用 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 开始频繁超时。监控表明,对于 EC2 运行,Node.js API、CPU 利用率仍然低于 10%。因此,我的重点是数据库和 API 与数据库的绑定。
我试图增加(并为此减少)node-postgres“最大”连接设置,但 API response/timeout 行为没有变化。我也试过在 RDS 上配置 IOPS,但没有改善。另外,有趣的是,我将 RDS 扩展到 m4.10xlarge(160 GB 内存,40 vCPUs),虽然 RDS CPU 利用率大幅下降,但 API 严重恶化(甚至无法支持我使用较小的 RDS 能够达到的每分钟 5000 个请求)。
我在很多方面都不熟悉,并且不确定在每分钟超过 5000 个请求时如何最好地确定这些移动部件中的哪些是瓶颈 API 性能。如前所述,我已尝试根据对 Postgresql 配置文档和 node-postgres 文档的审查进行各种调整,但无济于事。
如果有人对如何诊断或优化有任何建议,我将不胜感激。
更新
扩展到 m4.10xlarge 后,我执行了一系列负载测试,改变 request/min 的数量和每个池中的最大连接数.以下是监控指标的一些屏幕截图:
为了支持超过 5k 的请求,同时保持相同的响应率,您需要更好的硬件...
简单的数学表明:
5000 requests*190ms avg = 950k ms divided into 16 cores ~ 60k ms per core
这基本上意味着您的系统负载很高。
(我猜你有一些空闲 CPU 因为网络浪费了一些时间)
现在,您问题中真正有趣的部分来自放大尝试:m4.10xlarge(160 GB 内存,40 vCPUs)。
CPU 利用率的下降表明扩展释放了数据库时间资源 - 因此您需要推送更多请求!
2 条建议:
- 尝试将连接池增加到
max: 70
并查看网络流量(取决于您可能占用网络的数据量) - 另外,您对数据库的请求是从应用程序端异步请求的吗?确保您的应用实际上可以推送更多请求。
如果你对读性能感兴趣可以在两个(或多个)PostgreSQL实例之间设置复制,然后使用pgpool II在实例之间进行负载平衡。
水平扩展意味着如果您决定下周需要进行 10,000 次并发读取,您将不会开始达到 AWS 的最大实例大小。
您也开始在架构中获得一些高可用性。
--
很多时候人们会使用 pgbouncer 作为连接池,即使他们已经在他们的应用程序代码中内置了一个。 pgbouncer 工作得很好,通常更容易配置和管理 pgpool,但它不做负载平衡。不过,我不确定在这种情况下它是否对您有很大帮助。
最好的方法是根据调用的优先级为每个 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 调用使用正确的池,以获得最佳 service/connection 可用性。