psycopg2 默认不带连接池因其仅为驱动,只负责连接建立;正确配置 sqlalchemy 连接池需协同设置 pool_size、max_overflow、pool_recycle 和 pool_pre_ping 参数,避免连接泄漏与超时。

连接池配得不对,比没配还糟——不是连不上,而是连上了卡死、超时、泄漏全来。
为什么 psycopg2 默认不带连接池?
因为 psycopg2 本身只是个驱动,它只管“怎么连”,不管“连多少、怎么复用”。你每次调 psycopg2.connect(),就新建一个 TCP 连接 + 后端进程(PostgreSQL 每连一个 fork 一个),开销不小。没有池,等于每请求都重走一遍 TLS 握手、认证、内存分配。
- 不配池:100 并发 → 100 个连接同时打到 PostgreSQL,
max_connections很快耗尽 - 配了但乱设:比如
POOL_SIZE=50却没调max_connections,数据库直接拒绝新连接,报错fatal: remaining connection slots are reserved for non-replication superuser connections - 常见误区:以为“池越大越快”,结果连接堆积在 PgBouncer 或 DB 层,触发
idle_transaction_timeout或被 kill
SQLAlchemy 的 create_engine 连接池参数怎么设才不翻车?
用 SQLAlchemy 时,别只改 pool_size。它背后是 QueuePool,实际行为受多个参数联动影响:
-
pool_size:空闲连接保底数,建议设为应用平均并发请求数的 1.2–1.5 倍(比如常驻 30 QPS,设 40) -
max_overflow:紧急扩容上限,值 =max_connections−pool_size,不能为负;若 PostgreSQL 设了max_connections = 200,这里最多填 160 -
pool_recycle:强制回收连接,避免长连接因网络中断或 DB 重启变 stale;设3600(1 小时)比默认-1(永不过期)更稳 -
pool_pre_ping:设True,每次取连接前发个SELECT 1探活,代价小但能防“取到已断连接”导致的报错
示例:create_engine("postgresql://...", pool_size=40, max_overflow=60, pool_recycle=3600, pool_pre_ping=True)
高并发下用 pgxpool 还是 SQLAlchemy?
看你的瓶颈在哪:
- 如果瓶颈在 Python 层(比如大量同步阻塞 I/O、ORM 开销大),
SQLAlchemy+psycopg2够用,重点调好池参数 + 批量操作(execute_batch) - 如果瓶颈在连接建立/释放频率(比如微服务每秒几百次短查询),选
pgxpool(Go 实现)——它原生支持连接复用、细粒度超时、自动重试,且无 GIL 限制;Python 侧可通过 REST API 或 gRPC 调用封装好的 Go 服务 - 别混用:不要在同一个项目里既用
SQLAlchemy又手动起pgxpool,连接状态无法共享,反而增加管理复杂度
连接泄漏的典型现场和快速定位法
泄漏不是“忘了 .close()”这么简单。常见真凶:
- 用了
connection.cursor()但没cursor.close():尤其在异常路径里,游标没关,连接就一直被占着 - 用了
session.query(...).yield_per(n)但没遍历完就 return:SQLAlchemy 不会自动关底层连接 - 异步场景用
asyncpg却没 awaitpool.acquire()/pool.release():连接对象被 GC 前未归还,池里可用数越来越少
快速验证:查 PostgreSQL 当前连接:SELECT count(*) FROM pg_stat_activity WHERE state = 'idle in transaction'; 如果长期 >10,基本就是泄漏了。
最麻烦的不是调参,是连接生命周期和业务逻辑耦合太紧——比如一个 HTTP 请求开了连接,中间穿了 5 层函数,某一层 catch 了异常却没 propagate,连接就悬在那里。盯住 pg_stat_activity 和应用日志里的连接获取/释放时间戳,比盲目调 max_overflow 有用得多。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











