跳到主要内容

连接管理

PostgreSQL 每个连接都会占用数据库资源。云函数、云托管和其他弹性运行环境中,如果连接管理不当,容易出现连接数耗尽或请求排队。

连接复用

在 Node.js 中,应将连接池定义在模块顶层,让同一个运行时实例复用连接。

import pg from "pg";

export const pool = new pg.Pool({
host: process.env.PGHOST,
port: Number(process.env.PGPORT || 5432),
database: process.env.PGDATABASE,
user: process.env.PGUSER,
password: process.env.PGPASSWORD,
max: 5,
});

不要在每次请求内部创建新的连接池。

连接池大小

连接池并不是越大越好。需要按部署实例数估算总连接数:

总连接数 = 单实例连接池上限 × 最大实例数

如果云函数最多同时扩容到 20 个实例,每个实例连接池 max=5,理论上可能占用 100 个数据库连接。

释放连接

从连接池手动取出的 client 必须释放。

const client = await pool.connect();

try {
const result = await client.query("select now()");
return result.rows;
} finally {
client.release();
}

普通查询可以直接使用 pool.query(),由连接池自动借还连接。

超时设置

建议为业务查询设置合理超时,避免慢查询长期占用连接。

set statement_timeout = '5s';

也可以在应用层设置请求超时和重试策略。重试只适合幂等操作,写操作重试前需要确认是否可能重复写入。

监控连接

可以通过 pg_stat_activity 查看当前连接。

select state, count(*)
from pg_stat_activity
group by state
order by count(*) desc;

定位长时间运行的查询:

select pid, state, now() - query_start as duration, query
from pg_stat_activity
where state <> 'idle'
order by duration desc
limit 20;

常见问题

  • 连接数持续增长:检查是否每次请求创建新连接池,或手动连接未释放。
  • 大量 idle 连接:调小连接池上限和 idle 超时时间。
  • 查询排队:检查慢查询、锁等待和连接池上限。
  • 间歇性连接失败:检查网络、数据库连接上限和服务实例扩容情况。