
PgBouncer:将 PostgreSQL 扩展到 10,000+ 连接
PostgreSQL 为每个连接创建一个 OS 进程,每个进程消耗约 5-10MB RAM。PgBouncer 将数千个应用程序连接复用到一个小的数据库连接池中。
三种池化模式
会话池化:每个客户端会话对应一个服务器连接。支持 SET、咨询锁、LISTEN/NOTIFY。效率最低。适用于遗留应用。
事务池化(推荐):仅在事务期间分配服务器连接。效率提高 10-100 倍。无法使用会话级功能。
语句池化:每条语句后返回连接。仅自动提交。很少使用。
生产配置
[databases]
production = host=postgres.internal port=5432 dbname=appdb
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 5432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
default_pool_size = 25 # 每个数据库/用户对的服务器连接数
max_client_conn = 10000 # 最大应用程序连接数
reserve_pool_size = 5 # 用于突发流量的额外连接
max_db_connections = 100 # 每个数据库的总服务器连接数
server_connect_timeout = 15
client_idle_timeout = 600
server_idle_timeout = 600
server_lifetime = 3600
server_reset_query = DISCARD ALL
正确的池大小
公式:最佳连接数 = cpu_cores * 2(SSD)或 cpu_cores * 4(HDD)。超过此值,性能会因上下文切换开销而下降。
def calculate_pool_size(max_connections=200, num_instances=2, cpu_cores=8):
available = max_connections - 3 # 为超级用户保留
optimal = cpu_cores * 2
per_instance = available // num_instances
return {
'pool_size': min(optimal, per_instance),
'max_clients': per_instance * 200,
'reserve': max(5, per_instance // 5),
}
# 示例:8 CPU,200 max_connections,2 个实例
# 结果:pool_size=16, max_clients=2800

监控
psql -U pgbouncer -d pgbouncer
SHOW POOLS;
-- cl_waiting > 0:池已耗尽!客户端正在等待
-- maxwait > 100ms:连接延迟过高
-- sv_idle 高:池可能过大
SHOW STATS; -- req/s,平均查询时间
RELOAD; -- 无需重启即可应用配置
PAUSE production; -- 用于维护
RESUME production;
services:
pgbouncer-exporter:
image: prometheuscommunity/pgbouncer-exporter:latest
environment:
DATA_SOURCE_NAME: "postgresql://pgbouncer:pass@localhost:5432/pgbouncer"
# 关键告警:
# cl_waiting > 0 持续 => 池已耗尽
# maxwait_seconds > 0.1 => 连接延迟过高
事务模式限制
# 错误:预处理语句
# EXECUTE 可能在不同于 PREPARE 的服务器连接上运行
# 修复:conn = psycopg3.connect(dsn, prepare_threshold=None)
# 错误:SET search_path = myschema
# 下一个查询可能使用默认 search_path 运行
# 修复:ALTER USER appuser SET search_path TO myschema;
# 错误:咨询锁(pg_advisory_lock/unlock 在不同连接上)
# 修复:使用 SELECT FOR UPDATE 或 Redis 分布式锁
# 错误:LISTEN/NOTIFY
# 修复:为 LISTEN 使用专用的非池化连接

高可用性
backend pgbouncer_pool
mode tcp
balance leastconn
server pgbouncer1 10.0.0.1:5432 check
server pgbouncer2 10.0.0.2:5432 check
server pgbouncer3 10.0.0.3:5432 check
3 个 PgBouncer 实例 x 25 池大小 = 75 个总 PostgreSQL 连接,服务于 10,000+ 个应用程序连接。
故障排除指南
# "too many connections" 错误
psql -c "SELECT count(*) FROM pg_stat_activity;"
# 接近 max_connections:减少池大小或增加实例
# 切换到 PgBouncer 后查询变慢
psql -c "SHOW search_path;"
# 缺少会话配置:使用 ALTER USER/DATABASE 代替 SET
# 流量高峰期间池耗尽
watch -n1 'psql -U pgbouncer -d pgbouncer -c "SHOW POOLS;"'
# 增加 reserve_pool_size,减少 reserve_pool_timeout
PgBouncer 让一个 200 连接的 PostgreSQL 实例服务于数千个并发连接——这是可用基础设施变更中投资回报率最高的之一。