解决postgresql连接数不足
连接数不足是PostgreSQL运维中最常见的性能瓶颈之一。当客户端报错FATAL: remaining connection slots are reserved for non-replication superuser connections
时,意味着数据库已无法承载新请求。本文将从紧急处置、参数调优、连接池技术、内存优化、架构设计五个层面展开解决方案,并附实操代码示例。
一、问题根源:为什么连接数会爆?
-
硬件/配置限制
- 每个PostgreSQL连接消耗约10MB内存,默认
max_connections=100
,超限即拒绝新连接。 - 长事务、锁竞争或慢查询导致连接长时间占用不释放。
- 每个PostgreSQL连接消耗约10MB内存,默认
-
连接泄漏
- 应用层未正确关闭数据库连接(如PHP脚本异常退出、Java连接池配置错误)。
- 网络闪断导致TCP半开连接(需配置
tcp_keepalives_idle=60
)。
二、紧急救火:快速释放连接
适用场景:生产环境突发连接阻塞,需立即恢复服务。
-- 1. 查看当前连接与占用进程
SELECT * FROM pg_stat_activity;-- 2. 终止非关键进程 (替换$PID)
SELECT pg_terminate_backend($PID);-- 3. 阿里云/腾讯云用户可通过控制台一键清理
风险提示:避免终止复制或核心事务进程!建议优先终止
state='idle'
的空闲连接。
三、参数调优:根治连接数瓶颈
核心配置(修改postgresql.conf
后需重启):
# 提升最大连接数 (根据内存调整)
max_connections = 500 # 默认100,建议不超过1000# 自动清理空闲连接 (避免长时间占用)
idle_in_transaction_session_timeout = 10min # 自动终止空闲事务# 启用TCP Keepalive防僵尸连接
tcp_keepalives_idle = 60 # 60秒无活动发起探测
tcp_keepalives_interval = 10 # 探测间隔
tcp_keepalives_count = 10 # 探测失败次数
内存换算公式:
所需内存 ≈ max_connections × (work_mem + temp_buffers + 10MB)
若内存不足,需同步调低
work_mem
(如32MB→16MB)。
四、连接池:低成本应对高并发的银弹 📌
为什么需要连接池?
- 直接连接:每个请求独占一个DB连接,
max_connections
极易触顶。 - 连接池模式:应用层连接池(如C3P0) → 中间件连接池(推荐) → DB连接复用。
推荐方案:
- PgBouncer(轻量级)
# 配置连接池模式 (transaction/pool/session) pool_mode = transaction # 事务结束即释放连接 max_client_conn = 2000 # 客户端连接数 default_pool_size = 50 # 每个DB连接池大小
- Pgpool-II(支持读写分离)
connection_cache = on num_init_children = 200 # 子进程数 max_pool = 4 # 每个子进程连接池大小
实测效果:当连接池大小为50时,可支撑2000+应用线程,TPS提升4倍。
五、内存优化:节省连接资源的黑科技
- 启用Huge Pages
- 减少PageTable内存占用(尤其连接数>500时)
# postgresql.conf huge_pages = try
- 监控与防OOM
- 使用
pg_top
实时查看连接内存占用 - 设置cgroup限制PostgreSQL内存
- 使用
六、架构升级:分布式方案应对百万连接
当单机连接数突破2000时,应考虑:
- 读写分离
- 用Pgpool或HAProxy分流读请求。
- 分库分表
- Citus扩展实现水平分片。
- 连接卸载
- 将计算逻辑下推至应用层(如PL/Python)。