PostgreSQL 连接池耗尽排查:pg_stat_activity、idle in transaction 与连接上限

举报
yd_282288291 发表于 2026/11/11 08:39:41 2026/11/11
【摘要】 从 max_connections、连接池和应用实例数四层限制讲起,给出 pg_stat_activity 按状态与按会话的排查 SQL,总结连接泄漏、空闲事务、PgBouncer 事务模式的常见坑,并列出可兜底的超时参数。

一、先看清“连接耗尽”是哪一层

PostgreSQL 报 FATAL: sorry, too many clients already,或者应用侧一直 connection timeout,通常不是单一原因。连接数至少有四层限制:

  • 数据库 max_connections;
  • 单个应用连接池的 max_size;
  • 应用实例数量 × 每实例连接数;
  • 中间件(PgBouncer、云数据库代理)的连接上限。

很多事故是“扩容后连接数翻倍”导致的:实例从 2 个扩到 10 个,每个池仍然 20 条连接,数据库瞬间多出 160 条空闲连接。排查时先把这四层数字列出来,再决定调哪一层。

二、用 pg_stat_activity 找连接都在干什么

第一条 SQL 是按状态分组:

SELECT state, count(*)
FROM pg_stat_activity
WHERE backend_type = 'client backend'
GROUP BY state
ORDER BY count(*) DESC;

如果 idle 很多,说明连接池开得比实际并发大;如果 idle in transaction 很多,说明事务开启后没有及时提交或回滚;如果 active 长时间不降,通常是慢查询或锁等待。

继续定位具体会话:

SELECT pid, usename, application_name, client_addr,
       state, wait_event_type, wait_event,
       now() - xact_start AS xact_age,
       now() - query_start AS query_age,
       left(query, 80) AS query_head
FROM pg_stat_activity
WHERE state <> 'idle'
ORDER BY xact_age DESC NULLS LAST
LIMIT 30;

idle in transaction 是最危险的状态:它占着连接、可能持有锁,还会阻止 vacuum 回收。应用里“先 begin,再调用外部接口,最后 commit”的写法最容易制造这种会话。

三、连接池泄漏的几个高频原因

  1. 异常路径没有归还连接:拿到连接后抛异常,finally 里没有 close();
  2. 事务没有结束:BEGIN 后某个分支直接 return,连接回到池里仍处于事务中;
  3. 用了 session 级设置:SET search_path、临时表、 advisory lock 没清理,连接被复用时状态污染;
  4. 长连接 + 网络抖动:客户端以为连接还活着,服务端已经断开,池里出现半死连接;
  5. 连接池配置太小:并发一高就排队,表现为“超时”而不是“连接耗尽”。

排查时给连接池加两个指标:当前借出数、等待队列长度。借出数长期贴近上限、等待队列持续增长,就说明池太小或连接归还太慢,而不是数据库连不上。

四、几个能兜底的参数

-- 空闲事务超过 60 秒自动断开
ALTER SYSTEM SET idle_in_transaction_session_timeout = '60s';

-- 单条语句最长 30 秒
ALTER SYSTEM SET statement_timeout = '30s';

-- PG14+:普通空闲连接超过 10 分钟断开
ALTER SYSTEM SET idle_session_timeout = '10m';

这些参数是“止损”,不是“修复”。真正要改的是事务边界:不要在事务里做 RPC、发消息、等用户输入;批量任务分段提交;连接池借出和归还必须成对出现。

五、PgBouncer 的 transaction 模式要注意什么

transaction 模式下,一条连接只在事务期间绑定给某个客户端,事务结束就归还。它能把连接数压得很低,但有两个代价:

  • 会话级状态不能跨事务保留,SET、临时表、prepared statement 可能失效;
  • 应用不能依赖 session 级的 advisory lock 或游标。

如果业务大量使用 prepared statement,要么开启 PgBouncer 的协议级支持,要么改用 session 模式并接受更高的连接占用。

六、监控与处置顺序

建议至少监控:pg_stat_activity 按状态计数、连接数 / max_connections 使用率、idle in transaction 数量、最老事务年龄。

出现告警时的处置顺序:

  1. 先看是否某类 idle in transaction 暴涨,必要时终止最老的空闲事务;
  2. 再看应用实例数和连接池配置是否匹配;
  3. 最后才考虑调大 max_connections,因为每条连接都有内存和调度开销,盲目调大可能让问题更糟。

连接耗尽的本质通常是“连接被占着但没干活”。把事务缩短、把归还可视化、把超时配上,比单纯扩容更有效。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。