PgBouncer是PostgreSQL生态中最常用的连接池中间件,它的核心价值在于用一组固定的后端连接服务大量客户端,避免每个请求都重新建立连接、分配进程。PostgreSQL是进程模型,每个连接对应一个后端进程,内存开销通常在几MB到十几MB,当应用并发量上来之后,直接连接数据库的方式很快就会把连接数打满,出现too many clients already错误。通过PgBouncer做一层代理,成千上万的客户端连接可以复用几十个后端连接,内存占用和连接建立开销都大幅下降。

三种池化模式怎么选
pool_mode是PgBouncer最核心的参数,它决定了连接在什么粒度上被复用,共有三种取值:session、transaction和statement。session模式下,客户端断开连接之前始终独占一个后端连接,等于只做了连接复用,没有做并发收敛,能缓解的只有频繁建连的问题。transaction模式在事务结束时归还连接,下一个事务可能由其他客户端使用同一个后端连接,这是最常用的模式。statement模式更激进,每条语句执行完就归还连接,强制自动提交,多语句事务无法使用。
绝大多数Web应用推荐transaction模式,配合应用自带的连接池可以形成两级池化。需要注意transaction模式下有一些兼容性限制:prepared statements、SET和RESET ALL、LISTEN/NOTIFY、advisory lock等会话级特性都会出问题,因为下一个事务可能被路由到不同的后端连接。如果应用确实依赖这些特性,可以考虑升级到较新版本的PgBouncer,它支持协议级别的prepared statements,通过max_prepared_statements参数在transaction模式下正确处理命名prepared statement。
核心参数配置详解
下面是一份生产环境常用的配置文件示例,基于transaction模式:
[pgbouncer] listen_addr = 0.0.0.0 listen_port = 6432 auth_type = scram-sha-256 auth_file = /etc/pgbouncer/userlist.txt admin_users = pgbouncer_admin pool_mode = transaction max_client_conn = 5000 default_pool_size = 40 min_pool_size = 10 reserve_pool_size = 10 reserve_pool_timeout = 3 max_db_connections = 60 server_reset_query = DISCARD ALL server_idle_timeout = 300 server_lifetime = 3600 query_wait_timeout = 120 client_idle_timeout = 600 server_connect_timeout = 5 log_pooler_errors = 1 ignore_startup_parameters = extra_float_digits
max_client_conn是PgBouncer自身能接受的前端连接上限,这个值可以设置得比较大,比如5000甚至更高,因为PgBouncer处理空闲连接的成本极低。真正的关键是default_pool_size,它决定了每个数据库和用户组合对应的后端连接数。这个值需要结合PostgreSQL的max_connections来计算:假设数据库上还有其他直连业务,留给PgBouncer的配额是80,那么default_pool_size设置在40到50比较合理,再乘以可能的数据库数量,确保总后端连接不超过max_connections的百分之八十。
reserve_pool_size是应急用的保留连接,当默认池的连接全部繁忙且等待时间超过reserve_pool_timeout秒时,才会临时借用保留连接。这个机制可以应对突发流量,但要控制大小,否则等于变相绕过了池化限制。server_lifetime建议设置在1小时左右,定期重建后端连接可以释放连接上积累的会话状态,配合负载均衡器做优雅重启也更方便。
transaction模式下的避坑要点
transaction模式最大的坑是prepared statements。Java的JDBC驱动、psycopg2的默认行为都会使用命名prepared statement,语句在事务结束后被丢弃时,PgBouncer可能把它路由到另一个还没创建该语句的连接上,直接报错prepared statement does not exist。解决方案有三种:升级PgBouncer并配置max_prepared_statements;让应用改用扩展协议的匿名参数化语句;或者在JDBC连接串中设置prepareThreshold等于0来禁用服务端预编译。
另一个常见问题是应用层连接池与PgBouncer的配置冲突。应用侧的HikariCP的maximumPoolSize应该按业务并发数设置,而不是按数据库连接数设置,因为真正的数据库连接瓶颈由default_pool_size控制。如果应用侧每个实例开200个连接,后端池却只有40个,多余的连接只会在PgBouncer排队,白白占用内存。一般建议应用总连接数略小于max_client_conn,而default_pool_size按照数据库实际能承受的并发来定,通常几十个就足够支撑高TPS业务,因为事务执行时间往往只有几毫秒。
监控与验证配置效果
PgBouncer自带管理库,用psql连到pgbouncer这个虚拟数据库即可查看运行状态:
-- 连接管理接口 psql -p 6432 pgbouncer pgbouncer_admin -- 查看每个池的连接使用情况 SHOW POOLS; -- 查看当前活跃的服务端连接 SHOW SERVERS; -- cl_waiting表示排队等待的客户端数 -- 如果长期大于0,说明default_pool_size偏小 -- 查看统计信息,用于容量评估 SHOW STATS;
重点观察SHOW POOLS输出中的cl_waiting列,它是正在等待后端连接的客户端数量。如果这个值持续大于零,说明池子太小,需要提高default_pool_size或者优化慢查询。反过来,如果服务端连接长期大量空闲,可以适当收缩池子,把配额让给其他业务。SHOW STATS中的total_query_time与total_xact_count的比值可以估算平均事务耗时,帮助你判断当前的池大小是否能满足吞吐目标。
配置完成后建议做一轮压测验证,用pgbench或者业务压测工具模拟真实并发,对比直连和经过PgBouncer的TPS与P99延迟。压测时注意观察PostgreSQL端的pg_stat_activity视图,确认后端连接数稳定在预期范围内,没有出现连接风暴。如果一切正常,你会看到数据库连接数从几百降到几十,而应用侧的并发能力不受影响,这就是连接池优化带来的直接收益。
PgBouncerPostgreSQL连接池连接池配置修改时间:2026-09-05 09:26:40