PgBouncer PostgreSQL连接池配置:让多应用共享数据库不崩溃

概述

你跑过几个服务,每个服务都要连同一个PostgreSQL数据库?PostgreSQL默认max_connections只有100,加上保留连接,实际可用也就90个左右。几个应用一挤,数据库直接拒绝新连接,报错"too many connections for role"。

PgBouncer是一个轻量级PostgreSQL连接池。它站在数据库前面,把多个客户端的连接复用成少量数据库连接。配置简单,资源占用几乎可以忽略,特别适合VPS环境。

准备工作

  • 一台运行Ubuntu 22.04+或Debian 12+的VPS
  • Docker和Docker Compose已安装
  • 一个正在运行的PostgreSQL实例(端口默认5432)
  • 能访问该PostgreSQL的数据库账号(建议用专用连接池账号)

如果还没装Docker,跑一行:curl -fsSL https://get.docker.com | sudo sh

步骤

第一步:创建PgBouncer配置目录

mkdir -p ~/pgbouncer/conf ~/pgbouncer/data

第二步:写pgbouncer.ini配置文件

cat <<'EOF' | sudo tee ~/pgbouncer/conf/pgbouncer.ini
[databases]
# 格式:数据库名 = host:port
mydb = host=127.0.0.1 port=5432 dbname=mydb

[pgbouncer]
# 监听地址和端口
listen_addr = 0.0.0.0
listen_port = 6432

# PostgreSQL管理员密码(用于SHOW STATS等管理命令)
admin_users = pgbouncer
stats_users = pgbouncer

# 连接池模式:session/transaction/query
# transaction最常用,一个连接同时服务多个客户端
pool_mode = transaction

# 最大连接数(数据库侧)
max_connections = 50

# 每个池的最大连接数
default_pool_size = 10

# 客户端超时(秒),0表示不限制
client_idle_timeout = 0
client_login_timeout = 60

# 日志
log_connections = 1
log_disconnections = 1
logfile = /var/log/pgbouncer/pgbouncer.log

# 管理员密码文件
auth_file = /etc/pgbouncer/userlist.txt
auth_type = md5
EOF

第三步:创建用户认证文件

# 生成密码哈希:md5("密码+用户名")
PGPASSWORD=your_password psql -h 127.0.0.1 -U postgres -d mydb -tAc "SELECT '\"pgbouncer\" '||md5('your_password')" > /dev/null

# 更简单的方法:直接用md5sum
echo '"pgbouncer" "md5'$(echo -n "your_password+pgbouncer" | md5sum | awk '{print $1}')'"' > ~/pgbouncer/conf/userlist.txt
echo '"mydb_user" "md5'$(echo -n "db_password+mydb_user" | md5sum | awk '{print $1}')'"' >> ~/pgbouncer/conf/userlist.txt

实际使用中,更推荐在PostgreSQL里创建专用账号:

# 在PostgreSQL里执行
CREATE USER pgbouncer WITH PASSWORD 'your_password';
GRANT PgBouncer TO pgbouncer;  -- PostgreSQL 16+
-- 或者PG15及以下:
GRANT SELECT ON pg_stat_statements TO pgbouncer;

第四步:用Docker Compose启动PgBouncer

cat <<'EOF' | sudo tee ~/pgbouncer/docker-compose.yml
version: '3.8'
services:
  pgbouncer:
    image: edoburu/pgbouncer:1.22.1
    container_name: pgbouncer
    restart: unless-stopped
    ports:
      - "6432:6432"
    volumes:
      - ./conf/pgbouncer.ini:/etc/pgbouncer/pgbouncer.ini:ro
      - ./conf/userlist.txt:/etc/pgbouncer/userlist.txt:ro
    environment:
      - DATABASE_URL=postgres://mydb_user:db_password@postgres:5432/mydb?sslmode=disable
    depends_on:
      - postgres
    networks:
      - pgb_net

networks:
  pgb_net:
    driver: bridge
EOF

把postgres换成你实际PostgreSQL容器的主机名或IP。如果PostgreSQL在宿主机上,用host.docker.internal(Docker Desktop)或直接用宿主机IP。

第五步:启动服务

cd ~/pgbouncer
docker compose up -d

查看日志确认启动正常:

docker compose logs -f pgbouncer

看到类似输出就说明OK:

2026-08-10 13:51:00.123 UTC [1] LOG file descriptor: 10
2026-08-10 13:51:00.124 UTC [1] LOG paused: 0, in: 0, out: 0
2026-08-10 13:51:00.125 UTC [1] LOG loaded 2 connections

第六步:客户端连接方式变更

以前连数据库:

psql -h 192.168.1.100 -p 5432 -U mydb_user -d mydb

现在改连PgBouncer端口:

psql -h 192.168.1.100 -p 6432 -U mydb_user -d mydb

应用层的数据库连接地址也改一下端口号即可,其他不用变。

验证

# 1. 检查PgBouncer进程状态
docker compose ps pgbouncer

# 2. 查看连接池统计(需要psql连6432端口)
psql -h 127.0.0.1 -p 6432 -U pgbouncer -d pgbouncer -c "SHOW STATS;"

# 3. 查看当前活跃连接
psql -h 127.0.0.1 -p 6432 -U pgbouncer -d pgbouncer -c "SHOW CLIENTS;"

# 4. 查看池状态
psql -h 127.0.0.1 -p 6432 -U pgbouncer -d pgbouncer -c "SHOW POOLS;"

SHOW POOLS输出示例:

 database  | user   | cl_active | cl_waiting | sv_active | sv_idle | sv_used | sv_tested | sv_login | maxwait
-----------+--------+-----------+------------+-----------+---------+---------+-----------+----------+-------
 mydb      | mydb_user | 3        | 0          | 2         | 8       | 0       | 0         | 0        | 0
  • cl_active:当前活跃的客户端连接数
  • sv_active:当前活跃的数据库侧连接数
  • sv_idle:空闲的数据库连接,可以随时复用

如果cl_waiting不为0,说明客户端在排队等连接,需要调大default_pool_size。

常见问题

Q:连接报错"FATAL: no pg_hba.conf entry for host"

PgBouncer连PostgreSQL时,需要在PostgreSQL的pg_hba.conf里放行PgBouncer所在IP:

# 在PostgreSQL服务器上加一行
echo "host all all 172.18.0.0/16 md5" >> /var/lib/postgresql/data/pg_hba.conf
# 或者Docker方式
docker exec -it postgres sh -c "echo 'host all all 172.18.0.0/16 md5' >> data/pg_hba.conf"
docker exec -it postgres systemctl reload postgresql

Q:应用连上后查询报错"server closed the connection unexpectedly"

可能是pool_mode设置不当。如果应用用了事务外的连接(比如准备语句),transaction模式会有问题。试试改成session模式,但会占用更多数据库连接:

pool_mode = session

Q:怎么查看PgBouncer实时日志?

docker compose logs -f pgbouncer
# 或者看宿主机日志文件
tail -f ~/pgbouncer/logs/pgbouncer.log

Q:PgBouncer重启后连接断开怎么办?

PgBouncer重启会断开所有客户端连接。应用层需要有重连机制。大多数现代ORM和驱动都支持自动重连,检查一下配置里有没有reconnect=true或类似选项。

Q:max_connections设多少合适?

一个经验公式:max_connections = 数据库可用连接数 × 0.7。比如数据库max_connections=100,PgBouncer的max_connections设70左右比较安全,留30给管理操作和突发流量。

总结

PgBouncer配置简单,几行配置文件就能跑起来。核心就三件事:指定后端数据库地址、设置pool_mode、控制max_connections。把应用的数据库端口从5432改成6432,剩下的交给PgBouncer。

你的应用有没有遇到连接数不够的问题?试试看。

这篇文章对你有帮助吗?