
当业务并发突然升高时,PostgreSQL 的瓶颈不一定来自慢 SQL,也可能来自连接创建、认证和进程调度本身。本文用 PgBouncer 连接池部署流程,说明如何把应用侧大量短连接收束为少量稳定数据库连接,帮助你降低高并发下的连接开销。
典型现象是:CPU 没有打满,磁盘 I/O 也不高,但数据库连接数快速接近上限,应用日志开始出现 too many clients already。PgBouncer 不替代索引优化,却能把“频繁建连”从数据库主进程前移到专门代理层处理。
为什么 PostgreSQL 高并发容易被连接数拖慢
PostgreSQL 采用多进程模型,每个客户端连接通常对应一个后端进程。连接数量从几十个增长到几百个时,数据库需要承担更多内存占用、上下文切换和认证开销。如果应用服务配置了 8 个实例,每个实例连接池上限是 50,那么会制造 400 个数据库连接;即使大部分连接处于空闲状态,也会持续占用资源。
你可以先用下面的 SQL 看当前连接分布:
SELECT state, count(*)
FROM pg_stat_activity
GROUP BY state
ORDER BY count(*) DESC;
如果 idle 或 idle in transaction 数量长期偏高,说明应用侧连接释放或事务边界可能存在问题;如果活跃连接不多但总连接很高,连接池通常能带来改善。更多容量规划思路,可以参考服务器运维内容。

部署前先确认三件事
PgBouncer 很轻量,但它位于应用和数据库之间,部署前要先确认业务能接受哪种连接池模式。PgBouncer 常见模式有 session、transaction 和 statement。实际生产中,transaction 模式最常用,因为它在事务结束后释放后端连接,能显著提高复用率;但如果应用依赖会话级状态,例如临时表、会话变量、长事务或服务端 prepared statement,就要谨慎验证。
部署前建议完成这组检查:
- 连接上限:统计应用实例数、每个实例连接池上限和 PostgreSQL
max_connections,例如 8×50 是否已经超过数据库承载能力。 - 事务行为:抽样检查是否存在超过 30 秒的长事务,命令可用
SELECT now()-xact_start, query FROM pg_stat_activity WHERE xact_start IS NOT NULL;。 - 故障回退:保留应用直连数据库的配置项,确保代理异常时可以在 5 分钟内切回原连接地址。
- 认证方式:确认 PostgreSQL 当前使用
md5、scram-sha-256还是证书认证,避免 PgBouncer 用户表与数据库认证方式不一致。
如果数据库部署在 VPS(虚拟专用服务器)或独服(独立物理服务器)上,还要评估网络路径。PgBouncer 可以与应用同机、与数据库同机,或部署在单独代理节点。对中小规模业务来说,先放在应用与数据库同一内网环境中,减少额外网络跳数,通常更容易排障。涉及主机方案选择时,可结合VPS(虚拟专用服务器)主机相关内容判断资源弹性和隔离需求。
安装 PgBouncer 并准备最小可用配置
以下示例以常见 Linux 服务器为例,路径和服务名可能因发行版不同略有差异。生产前建议先在预发布环境完整跑一遍应用登录、下单、后台查询和定时任务。
sudo apt update
sudo apt install -y pgbouncer
sudo systemctl enable pgbouncer
核心配置通常位于 /etc/pgbouncer/pgbouncer.ini。一个最小可用配置可以这样开始:
[databases]
appdb = host=127.0.0.1 port=5432 dbname=appdb
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 50
reserve_pool_size = 10
reserve_pool_timeout = 3
server_reset_query = DISCARD ALL
ignore_startup_parameters = extra_float_digits
这里有两个参数最容易被误配。max_client_conn 是 PgBouncer 接收的客户端连接上限,不等于数据库真实连接数;default_pool_size 才是每个数据库、每个用户对应的后端连接池大小。假设你只有一个业务库和一个业务用户,default_pool_size=50 意味着 PgBouncer 最多向 PostgreSQL 保持约 50 条常规后端连接,而应用侧可以连接到 PgBouncer 的数量则由 max_client_conn 控制。

用户认证、应用改造和灰度切换
PgBouncer 的认证文件必须与数据库用户和认证算法匹配。可以查询用户密码哈希,再写入 /etc/pgbouncer/userlist.txt。示例格式如下:
"app_user" "SCRAM-SHA-256$4096:example-salt$example-stored-key:example-server-key"
不要把上面的示例值直接用于生产,它只是格式说明。更新认证文件后执行:
sudo systemctl restart pgbouncer
psql -h 127.0.0.1 -p 6432 -U app_user -d appdb -c "SELECT 1;"
应用侧通常只需要把数据库端口从 5432 改为 6432,主机名改为 PgBouncer 地址。建议按“单实例灰度→半数实例→全部实例”切换,每一步观察 10 到 15 分钟,重点看错误率、连接数和平均响应时间。
PgBouncer 自带管理库,可以直接查看连接池是否正常复用:
psql -h 127.0.0.1 -p 6432 -U pgbouncer pgbouncer -c "SHOW POOLS;"
psql -h 127.0.0.1 -p 6432 -U pgbouncer pgbouncer -c "SHOW STATS;"
如果 cl_active 很高而 sv_active 维持在可控范围,说明前端连接已经被有效收束;如果 wait_clients 持续增长,说明后端池太小、SQL 太慢,或事务没有及时结束。此时不要盲目把 default_pool_size 从 50 提到 300,因为这会把压力重新推回 PostgreSQL。你应该先结合慢查询日志和 pg_stat_activity 找出等待来源。网站性能排查也可以延伸阅读TTFB 与主机优化指南,把数据库连接、后端处理和前端首字节时间一起观察。
参数建议:先控制连接,再扩大吞吐
PgBouncer 参数没有通用固定值。小型业务可以从 default_pool_size=20 开始,中型业务常见范围是 50 到 100。关键是让后端连接数保持在 PostgreSQL 能稳定处理的区间。
一套实用起点如下:
pool_mode=transaction:适合多数 Web 请求,每个事务结束后释放后端连接,连接复用率更高。max_client_conn=1000:允许应用侧短连接进入队列,但需要配合系统ulimit -n,建议文件描述符上限至少 4096。default_pool_size=50:先保护数据库,观察wait_clients后再按 10 或 20 的步长调整。query_timeout=60:避免异常请求长期占用后端连接,具体值应与业务接口超时时间一致。
如果你使用的是云服务器(弹性计算服务器)或多节点应用,建议把应用自身连接池也同步调小。例如每个实例 maximumPoolSize=50,接入后可先降到 10 到 20。WordPress、论坛或多租户站点,也可参考WordPress 运维与优化文章中的后端瓶颈排查思路。

常见故障与排查路径
上线 PgBouncer 后,最常见的问题不是服务启动失败,而是应用行为与连接池模式不匹配。比如 transaction 模式下,应用如果依赖会话级 prepared statement,就可能出现偶发查询错误;如果存在 idle in transaction,后端连接会被长时间占住,连接池效果会明显下降。
遇到异常时,可以按这个顺序排查:
- 先确认代理可用:执行
systemctl status pgbouncer和ss -lntp | grep 6432,排除服务未监听。 - 再看认证问题:如果日志出现
password authentication failed,检查/etc/pgbouncer/userlist.txt与数据库用户密码是否同步。 - 接着看连接等待:
SHOW POOLS;中wait_clients超过 0 且持续增长,优先检查慢 SQL 和长事务。 - 最后看应用兼容:如果只在某些接口报错,临时把该应用切回直连数据库,对比是否与
pool_mode有关。
什么时候不应该优先上 PgBouncer
PgBouncer 解决的是连接管理问题,不是所有数据库性能问题的答案。如果慢查询占比高、索引缺失、单表扫描过大,连接池只会让更多请求排队进入数据库,不能降低单次查询成本。上线前建议先用 EXPLAIN ANALYZE 找出耗时 SQL,并确认连接数确实是主要矛盾。
如果业务大量依赖长连接会话、临时表、LISTEN/NOTIFY 或复杂事务,transaction 模式也可能不适合,需要退回 session 模式,连接复用收益会降低。对于总连接数长期低于 50 的站点,PgBouncer 带来的运维复杂度可能高于收益,此时更推荐先完善备份、监控和慢查询日志。
总结:把 PgBouncer 当成连接治理工具,而不是万能加速器
总结来看,PgBouncer 连接池适合解决“应用短连接太多、数据库连接数过高、认证和进程调度开销偏大”的问题。推荐做法是先统计连接来源和事务行为,再以 transaction 模式、小步参数、灰度切换和可回滚配置上线。上线后持续观察 SHOW POOLS;、SHOW STATS;、pg_stat_activity 和应用错误率,确认连接数下降没有换来等待队列上升。
如果你需要为数据库密集型网站选择更稳定的运行环境,可在 Hostease 方案中把 PostgreSQL、应用服务和 PgBouncer 做资源隔离,并结合服务器性能优化、备份和监控规划。下一步建议先记录测试环境接入前后的连接数、95 分位响应时间和错误率,再推广到生产。