连接池到底该开多大
线上有个服务,压测的时候 QPS 上不去,第一反应是把连接池从 20 调到 100。结果 QPS 反而掉了三成。
原因不复杂:数据库的 CPU 核数是固定的。连接数超过核数之后,剩下的连接只是在争抢 CPU 时间片,还额外带来了上下文切换和锁竞争的开销。
一个粗略的起点
Postgres 官方文档里给过一个经验公式,大意是:
连接数 ≈ CPU 核数 × 2 + 有效磁盘数
4 核机器上差不多就是 9 到 10 个。听起来少得离谱,但对于 OLTP 负载,这个量级往往就够了。
关键在于:连接池的意义是「复用」,不是「并发」。真正需要几百并发的场景,通常是事务里做了不该做的事 —— 比如在事务中间调了一个外部 HTTP 接口。
先算清楚每个连接在干什么
我当时把慢查询日志打开看了一遍,发现有一半的事务持有时长超过 200ms,其中大部分时间花在等一个第三方接口上。这种情况加连接数只是把排队从应用层挪到了数据库层。
后来把那个调用挪到事务外面,池子还是 20,QPS 直接翻倍。
几个要盯的指标
-- 当前活跃连接
SELECT count(*) FROM pg_stat_activity WHERE state = active;
-- 等待事件分布
SELECT wait_event_type, wait_event, count(*)
FROM pg_stat_activity GROUP BY 1, 2 ORDER BY 3 DESC;
如果 wait_event 里大量出现 Lock 或者 IO,加连接数只会让情况更糟。如果是 ClientRead,说明连接在等应用发指令,那更该去看应用侧。
别忘了数据库侧的上限
max_connections 是数据库的总闸。所有应用实例的连接池加起来不能超过它,否则新连接会直接被拒。
还有个隐藏成本:Postgres 是每连接一个进程,每个进程大约占几 MB 内存。几百个连接就是几个 G,1G 内存的小机器上会直接把数据库压垮。