木杉笔记

记录后端、运维与数据库的踩坑日常

连接池到底该开多大

2026-09-05数据库

线上有个服务,压测的时候 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 内存的小机器上会直接把数据库压垮。