目标
当所有请求都在获取连接上超时、而数据库 CPU 只有 8% 时,问题出在客户端与服务器之间的连接池。PgBouncer 的管理命令用一条查询让看不见的队列现形:cl_waiting 是愤怒客户端数,sv_active 是真正忙碌的服务端连接数,两者的差距就是故事本身——池过小、客户端囤积或连接泄漏。
步骤要点
- 执行 SHOW POOLS,观察 cl_waiting 高企而 sv_active 未饱和,即可断定池耗尽而非数据库过载。
- 用 SHOW CLIENTS 按用户统计连接归属,找出独占池的那个部署。
- 统计 idle 状态客户端:大量 idle 无等待是客户端囤着不还;大量等待而 sv_idle 为 0 才是池真不够。
- 客户端侧给连接池设 max=10、idleTimeout=30s、connectionTimeout=5s,让占用可预测、获取有期限。
- 调整服务端池上限后 RELOAD 并复跑 SHOW POOLS:同负载下 cl_waiting 归零、sv_active 稳定在数据库真实可服务范围内。
排错提示
经 PgBouncer 事务模式下命名预处理语句会失效,要么走二进制协议要么把该库切成 session 模式;池调大后数据库反而饱和,说明池此前掩盖了数据库扛不住的并发,应回调池并修掉让客户端长时间持连接的慢查询;某个微服务总在囤连接就给它独立 pgbouncer 条目与独立上限,让坏客户端只饿自己。
适用边界
SHOW 统计需要配置 stats 用户并定期重置才好读;事务池化改变会话语义,依赖会话状态的特性需要 session 模式或重新设计。
代码示例
psql -p 6432 pgbouncer -c "SHOW POOLS;"
# Key columns:
# cl_active cl_waiting sv_active sv_idle maxused
# 3 214 20 0 20
# -> pool exhausted while servers are the real limit