PgBouncer 不读 PostgreSQL 的 pg_authid,它需要自己的用户清单。最简单的方式是用 md5 密码,密码串由「密码 + 用户名」拼出:
-- 在 PostgreSQL 里生成与 PgBouncer 兼容的 md5 串
SELECT 'md5' || md5('your_password' || 'appuser');
-- userlist.txt 内容(用户名 + 空格 + 引号包裹的 md5 串)
"appuser" "md5893b..."
如果后端使用了 SCRAM 认证(PostgreSQL 13+ 默认),可以把 auth_type 设为 scram-sha-256 并配合 auth_file 里的 scram 密码,或用 auth_user 让 PgBouncer 以代理身份动态查询 pg_shadow。生产环境推荐后者,避免明文维护密码清单。
六、监控与排障:SHOW 命令
PgBouncer 自带一套虚拟管理库,连上 6432 端口、用 admin_users 里的账号即可实时查看池状态:
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW POOLS;"
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW STATS;"
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW CLIENTS;"
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW SERVERS;"
关键看 SHOW POOLS 的 cl_active / cl_waiting / sv_active:cl_waiting 持续大于 0 说明前端在排队,通常是 default_pool_size 太小或后端慢查询堆积;sv_active 长期打满则说明后端 PostgreSQL 本身成为瓶颈,此时加 PgBouncer 无济于事,要先去查慢 SQL。
配合 PostgreSQL 侧的实时监控,能快速定位是「连接太多」还是「查询太慢」:
SELECT state, count(*) FROM pg_stat_activity GROUP BY state ORDER BY 2 DESC;
SELECT pid, state, wait_event_type, query FROM pg_stat_activity
WHERE state <> 'idle' ORDER BY query_start LIMIT 20;
七、常见误区对照
| 误区 | 正确做法 |
|---|---|
| transaction 模式下用临时表 | 临时表是会话级,事务结束即丢;改用普通表或应用内缓存 |
| default_pool_size 设得很大 | 它按库×用户计,过大反而压垮 PostgreSQL |
| PgBouncer 能解决慢 SQL | 它只收敛连接,后端瓶颈要靠索引与慢查询治理 |
| 忘了 server_reset_query | transaction 模式务必设 DISCARD ALL,避免会话状态泄漏 |
八、与 PostgreSQL 协同调优
引入 PgBouncer 后,PostgreSQL 的 max_connections 可以大胆调小(例如 200),把「海量前端连接」的缓冲任务交给 PgBouncer。这样每个后端连接都能分到更多 work_mem,复杂查询反而更快。一个经验公式:
PostgreSQL max_connections ≈ sum(default_pool_size × 库用户组合数) + 预留(20~50)
PgBouncer default_pool_size × 库用户数 ≪ PostgreSQL max_connections
例如 1 个库、1 个应用用户、default_pool_size=20,则后端稳定 20 条连接;前端哪怕来 5000 个并发连接,PostgreSQL 也只看到 20 条,内存与上下文切换开销骤降。
九、落地清单
| 步骤 | 动作 | 校验 |
|---|---|---|
| 1 | 选 pool_mode=transaction | 确认无会话级临时表/SET 依赖 |
| 2 | 部署 PgBouncer(Docker 或二进制) | 6432 端口可达 |
| 3 | 配置 userlist / auth_user | 应用用原账号能登录 |
| 4 | 设 default_pool_size,调小 PG max_connections | SHOW POOLS 无 cl_waiting |
| 5 | 接监控(SHOW STATS + pg_stat_activity) | 告警 cl_waiting / sv_active |
PgBouncer 是 PostgreSQL 高并发架构里性价比最高的组件之一:部署简单、零侵入、收益立竿见影。当你在面对连接风暴、内存被连接吃光、或想把微服务架构下的数据库连接数收敛下来时,它几乎总是第一选择。延伸阅读可参考本站 PostgreSQL 慢查询排查、PostgreSQL 备份与 PITR 恢复、PostgreSQL JSONB 实战,以及用 Docker 编排 与 VS Code 远程开发 搭建本地验证环境。
下面是一份生产可参考的 pgbouncer.ini,关键参数我都加了注释:
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 5000
default_pool_size = 20
min_pool_size = 5
reserve_pool_size = 5
reserve_pool_timeout = 3
server_idle_timeout = 60
server_lifetime = 3600
server_reset_query = DISCARD ALL
log_connections = 1
log_disconnections = 1
admin_users = pgb_admin
stats_users = pgb_stats
| 参数 | 含义 | 建议值 |
|---|---|---|
| default_pool_size | 每个用户+数据库组合保留的后端连接数 | 20(按并发调) |
| max_client_conn | PgBouncer 接受的前端连接上限 | 5000+ |
| reserve_pool_size | 主池满时临时借用的额外连接 | 5 |
| server_idle_timeout | 空闲后端连接回收时间(秒) | 60 |
| server_lifetime | 后端连接最大存活时间(秒),防长连接老化 | 3600 |
一个常见误区是 default_pool_size 设得过大——它本质是「每个库每用户」的后端连接数,若设成 100、又有 10 个库,后端实际连接会瞬间破千,反而把 PostgreSQL 打爆。原则是让 default_pool_size × 库用户数 远小于 PostgreSQL 的 max_connections。
五、认证配置 userlist.txt
PgBouncer 不读 PostgreSQL 的 pg_authid,它需要自己的用户清单。最简单的方式是用 md5 密码,密码串由「密码 + 用户名」拼出:
-- 在 PostgreSQL 里生成与 PgBouncer 兼容的 md5 串
SELECT 'md5' || md5('your_password' || 'appuser');
-- userlist.txt 内容(用户名 + 空格 + 引号包裹的 md5 串)
"appuser" "md5893b..."
如果后端使用了 SCRAM 认证(PostgreSQL 13+ 默认),可以把 auth_type 设为 scram-sha-256 并配合 auth_file 里的 scram 密码,或用 auth_user 让 PgBouncer 以代理身份动态查询 pg_shadow。生产环境推荐后者,避免明文维护密码清单。
六、监控与排障:SHOW 命令
PgBouncer 自带一套虚拟管理库,连上 6432 端口、用 admin_users 里的账号即可实时查看池状态:
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW POOLS;"
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW STATS;"
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW CLIENTS;"
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW SERVERS;"
关键看 SHOW POOLS 的 cl_active / cl_waiting / sv_active:cl_waiting 持续大于 0 说明前端在排队,通常是 default_pool_size 太小或后端慢查询堆积;sv_active 长期打满则说明后端 PostgreSQL 本身成为瓶颈,此时加 PgBouncer 无济于事,要先去查慢 SQL。
配合 PostgreSQL 侧的实时监控,能快速定位是「连接太多」还是「查询太慢」:
SELECT state, count(*) FROM pg_stat_activity GROUP BY state ORDER BY 2 DESC;
SELECT pid, state, wait_event_type, query FROM pg_stat_activity
WHERE state <> 'idle' ORDER BY query_start LIMIT 20;
七、常见误区对照
| 误区 | 正确做法 |
|---|---|
| transaction 模式下用临时表 | 临时表是会话级,事务结束即丢;改用普通表或应用内缓存 |
| default_pool_size 设得很大 | 它按库×用户计,过大反而压垮 PostgreSQL |
| PgBouncer 能解决慢 SQL | 它只收敛连接,后端瓶颈要靠索引与慢查询治理 |
| 忘了 server_reset_query | transaction 模式务必设 DISCARD ALL,避免会话状态泄漏 |
八、与 PostgreSQL 协同调优
引入 PgBouncer 后,PostgreSQL 的 max_connections 可以大胆调小(例如 200),把「海量前端连接」的缓冲任务交给 PgBouncer。这样每个后端连接都能分到更多 work_mem,复杂查询反而更快。一个经验公式:
PostgreSQL max_connections ≈ sum(default_pool_size × 库用户组合数) + 预留(20~50)
PgBouncer default_pool_size × 库用户数 ≪ PostgreSQL max_connections
例如 1 个库、1 个应用用户、default_pool_size=20,则后端稳定 20 条连接;前端哪怕来 5000 个并发连接,PostgreSQL 也只看到 20 条,内存与上下文切换开销骤降。
九、落地清单
| 步骤 | 动作 | 校验 |
|---|---|---|
| 1 | 选 pool_mode=transaction | 确认无会话级临时表/SET 依赖 |
| 2 | 部署 PgBouncer(Docker 或二进制) | 6432 端口可达 |
| 3 | 配置 userlist / auth_user | 应用用原账号能登录 |
| 4 | 设 default_pool_size,调小 PG max_connections | SHOW POOLS 无 cl_waiting |
| 5 | 接监控(SHOW STATS + pg_stat_activity) | 告警 cl_waiting / sv_active |
PgBouncer 是 PostgreSQL 高并发架构里性价比最高的组件之一:部署简单、零侵入、收益立竿见影。当你在面对连接风暴、内存被连接吃光、或想把微服务架构下的数据库连接数收敛下来时,它几乎总是第一选择。延伸阅读可参考本站 PostgreSQL 慢查询排查、PostgreSQL 备份与 PITR 恢复、PostgreSQL JSONB 实战,以及用 Docker 编排 与 VS Code 远程开发 搭建本地验证环境。
当你把应用从单体拆成微服务,或把定时任务从每天一次改成每秒一次,PgBouncer 往往是 PostgreSQL 最后一道防线。PostgreSQL 采用「一连接一进程」模型,每建立一个连接就要 fork 一个后端进程、分配约 5–10MB 内存,连接数一旦突破数百,连接风暴就会让数据库 CPU 飙升、响应变慢甚至 OOM。本文用一组可直接抄的配置,讲清如何用 PostgreSQL 连接池把成百上千的前端连接收敛到少量后端连接上,让数据库只看到稳定、可控的连接数。
一、为什么 PostgreSQL 需要连接池
PostgreSQL 每来一个客户端连接,服务端就 fork 一个独立后端进程。连接创建成本包含:身份验证、内存分配(work_mem、各类缓冲区)、上下文切换。实测在 2C4G 的实例上,把 max_connections 调到 1000,仅空闲连接就可能吃掉数 GB 内存,真正留给查询的内存反而被挤压。
而应用端往往倾向于「多开连接保平安」:Java 的 HikariCP、Python 的 SQLAlchemy、Node 的 pg 模块默认都倾向于维持较大的连接池。当流量抖动、超时重试叠加,瞬间产生大量短连接,数据库来不及回收,就会陷入连接风暴——典型症状就是 Too many connections 报错、pg_stat_activity 里堆满 idle in transaction。
PgBouncer 位于应用与数据库之间,把 N 个前端连接映射到 M 个后端连接(N≫M),让数据库侧只维持少量稳定连接。它自身是单进程、事件驱动的轻量代理,内存占用极低,一台 1G 内存的小机器就能轻松挡住上万个前端连接。
二、PgBouncer 的三种池化模式
PgBouncer 的核心差异在于「后端连接何时归还给池」,对应三种模式,直接决定你能不能用事务、临时表、SET 变量等会话级特性。
| 模式 | 连接复用粒度 | 事务语义 | 适用场景 |
|---|---|---|---|
| session | 整个会话期间独占一条后端连接 | 完整,支持临时表、SET、序列等 | 依赖会话级状态的传统应用 |
| transaction | 一个事务结束立即归还 | 仅在单事务内有效 | 绝大多数无状态 Web 应用(推荐) |
| statement | 单条语句结束即归还 | 不能跨语句保持事务 | 特殊只读/无状态查询(极少用) |
2.1 Session 模式
客户端连上后独占一条后端连接,直到断开。行为与直连数据库完全一致,但失去了连接复用能力,性能提升有限。只有在应用大量使用临时表、会话级 SET、自定义 GUC 变量、LISTEN/NOTIFY 时才需要它。
2.2 Transaction 模式(推荐)
一个事务提交或回滚后,后端连接立即归还池中供其他客户端复用。这是 Web 应用的黄金选择:绝大多数请求都是「建连→执行一条或几条 SQL→提交→断开」的短事务,复用率极高。代价是不能在事务外使用临时表、不能跨语句保持 SET 变量。
2.3 Statement 模式
每条语句执行完就归还连接,要求事务中同一时刻只能有一条语句在跑,因此基本无法使用多语句事务。仅适合极特殊的读多写少、完全无状态的场景,日常几乎不用。
三、用 Docker 快速起一个 PgBouncer
最省事的方式是用官方镜像起一个容器,把应用连接串从直连 5432 改成指向 PgBouncer 的 6432。下面是一个 docker-compose 示例:
services:
pgbouncer:
image: edoburu/pgbouncer:1.22
environment:
- DATABASES=mydb=host.docker.internal port=5432 dbname=mydb
- POOL_MODE=transaction
- MAX_CLIENT_CONN=5000
- DEFAULT_POOL_SIZE=20
- AUTH_TYPE=md5
ports:
- "6432:6432"
restart: unless-stopped
应用侧的 JDBC/连接串只需把端口改成 6432、host 指向 PgBouncer 即可,账号密码保持不变。注意 AUTH_TYPE 要与后端 PostgreSQL 的密码加密方式匹配,否则会出现密码认证失败。
四、核心配置参数解析
下面是一份生产可参考的 pgbouncer.ini,关键参数我都加了注释:
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 5000
default_pool_size = 20
min_pool_size = 5
reserve_pool_size = 5
reserve_pool_timeout = 3
server_idle_timeout = 60
server_lifetime = 3600
server_reset_query = DISCARD ALL
log_connections = 1
log_disconnections = 1
admin_users = pgb_admin
stats_users = pgb_stats
| 参数 | 含义 | 建议值 |
|---|---|---|
| default_pool_size | 每个用户+数据库组合保留的后端连接数 | 20(按并发调) |
| max_client_conn | PgBouncer 接受的前端连接上限 | 5000+ |
| reserve_pool_size | 主池满时临时借用的额外连接 | 5 |
| server_idle_timeout | 空闲后端连接回收时间(秒) | 60 |
| server_lifetime | 后端连接最大存活时间(秒),防长连接老化 | 3600 |
一个常见误区是 default_pool_size 设得过大——它本质是「每个库每用户」的后端连接数,若设成 100、又有 10 个库,后端实际连接会瞬间破千,反而把 PostgreSQL 打爆。原则是让 default_pool_size × 库用户数 远小于 PostgreSQL 的 max_connections。
五、认证配置 userlist.txt
PgBouncer 不读 PostgreSQL 的 pg_authid,它需要自己的用户清单。最简单的方式是用 md5 密码,密码串由「密码 + 用户名」拼出:
-- 在 PostgreSQL 里生成与 PgBouncer 兼容的 md5 串
SELECT 'md5' || md5('your_password' || 'appuser');
-- userlist.txt 内容(用户名 + 空格 + 引号包裹的 md5 串)
"appuser" "md5893b..."
如果后端使用了 SCRAM 认证(PostgreSQL 13+ 默认),可以把 auth_type 设为 scram-sha-256 并配合 auth_file 里的 scram 密码,或用 auth_user 让 PgBouncer 以代理身份动态查询 pg_shadow。生产环境推荐后者,避免明文维护密码清单。
六、监控与排障:SHOW 命令
PgBouncer 自带一套虚拟管理库,连上 6432 端口、用 admin_users 里的账号即可实时查看池状态:
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW POOLS;"
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW STATS;"
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW CLIENTS;"
psql -h 127.0.0.1 -p 6432 -U pgb_admin pgbouncer -c "SHOW SERVERS;"
关键看 SHOW POOLS 的 cl_active / cl_waiting / sv_active:cl_waiting 持续大于 0 说明前端在排队,通常是 default_pool_size 太小或后端慢查询堆积;sv_active 长期打满则说明后端 PostgreSQL 本身成为瓶颈,此时加 PgBouncer 无济于事,要先去查慢 SQL。
配合 PostgreSQL 侧的实时监控,能快速定位是「连接太多」还是「查询太慢」:
SELECT state, count(*) FROM pg_stat_activity GROUP BY state ORDER BY 2 DESC;
SELECT pid, state, wait_event_type, query FROM pg_stat_activity
WHERE state <> 'idle' ORDER BY query_start LIMIT 20;
七、常见误区对照
| 误区 | 正确做法 |
|---|---|
| transaction 模式下用临时表 | 临时表是会话级,事务结束即丢;改用普通表或应用内缓存 |
| default_pool_size 设得很大 | 它按库×用户计,过大反而压垮 PostgreSQL |
| PgBouncer 能解决慢 SQL | 它只收敛连接,后端瓶颈要靠索引与慢查询治理 |
| 忘了 server_reset_query | transaction 模式务必设 DISCARD ALL,避免会话状态泄漏 |
八、与 PostgreSQL 协同调优
引入 PgBouncer 后,PostgreSQL 的 max_connections 可以大胆调小(例如 200),把「海量前端连接」的缓冲任务交给 PgBouncer。这样每个后端连接都能分到更多 work_mem,复杂查询反而更快。一个经验公式:
PostgreSQL max_connections ≈ sum(default_pool_size × 库用户组合数) + 预留(20~50)
PgBouncer default_pool_size × 库用户数 ≪ PostgreSQL max_connections
例如 1 个库、1 个应用用户、default_pool_size=20,则后端稳定 20 条连接;前端哪怕来 5000 个并发连接,PostgreSQL 也只看到 20 条,内存与上下文切换开销骤降。
九、落地清单
| 步骤 | 动作 | 校验 |
|---|---|---|
| 1 | 选 pool_mode=transaction | 确认无会话级临时表/SET 依赖 |
| 2 | 部署 PgBouncer(Docker 或二进制) | 6432 端口可达 |
| 3 | 配置 userlist / auth_user | 应用用原账号能登录 |
| 4 | 设 default_pool_size,调小 PG max_connections | SHOW POOLS 无 cl_waiting |
| 5 | 接监控(SHOW STATS + pg_stat_activity) | 告警 cl_waiting / sv_active |
PgBouncer 是 PostgreSQL 高并发架构里性价比最高的组件之一:部署简单、零侵入、收益立竿见影。当你在面对连接风暴、内存被连接吃光、或想把微服务架构下的数据库连接数收敛下来时,它几乎总是第一选择。延伸阅读可参考本站 PostgreSQL 慢查询排查、PostgreSQL 备份与 PITR 恢复、PostgreSQL JSONB 实战,以及用 Docker 编排 与 VS Code 远程开发 搭建本地验证环境。




