连接池配置实战——从“连不上“到“连太多“的完整排查指南

十五年数据库相关经验,做过 DBA、架构师、技术顾问。不求"颠覆",只求"靠谱"。


翻过很多文档,也踩过很多坑。做 DBA 这些年,凌晨被叫醒的次数里,有三分之一跟连接池有关。

连接池这东西,配置好了默默无闻,配置错了要命。最常见的两个极端:一个是"连不上"------应用报连接超时,业务全挂;另一个是"连太多"------数据库被连接数打满,所有请求排队等。

这篇文章我把连接池相关的排查方法论整理出来,从"看到报错"到"定位配置问题",每一步都说清楚。


一、先分清两种报错:连不上 vs 连太多

接到连接池相关的告警,第一步是分清属于哪种情况。

连不上(连接耗尽):应用层报"无法获取数据库连接"或"连接超时"。根因通常是连接池里的连接不够用,或者数据库拒绝了新连接。

连太多(连接数打满):数据库层报"too many connections"或类似错误。根因通常是连接池配置过大,或者应用有连接泄漏。

怎么快速区分? 看报错来源。如果报错是应用层抛出的(比如 HikariCP 的 Connection is not available, request timed out),是"连不上"。如果报错是数据库返回的(比如 ERROR 1040: Too many connections),是"连太多"。

我的习惯 :接到连接告警,先登录数据库看一眼当前连接数。SHOW PROCESSLIST(MySQL)或者 SELECT count(*) FROM pg_stat_activity(PostgreSQL)。这个数字能帮你快速判断方向。


二、"连不上"排查------连接为什么不够用

应用报连不上,根因通常在以下几个方向。

原因 1:连接池大小配置太小

这是最直接的原因。连接池的最大连接数设得太小,扛不住当前的并发量。

举个例子:连接池最大连接数设了 10,但应用有 20 个线程同时需要数据库连接。多出来的 10 个线程只能排队等。如果等了太久(超过连接超时时间),就报超时错误。

怎么判断? 看连接池的监控指标。HikariCP 有 activeConnectionsidleConnections。如果 activeConnections 持续等于 maximumPoolSize,说明连接池已经满了。

怎么解决? 调大连接池的最大连接数。但要注意,不能无限制调大------数据库本身有最大连接数限制,而且连接数太多会消耗数据库的内存和 CPU。

经验公式:连接池大小 = ((核心数 × 2) + 有效磁盘数)。这是一个经验起点,具体还要根据实际压测结果调整。

原因 2:慢查询占住了连接

连接池大小没问题,但还是连不上。这时候要看看是不是慢查询把连接占住了。

场景:连接池有 50 个连接,正常情况下够用。但突然来了几条慢查询,每条查询执行 30 秒。这 30 秒里,这些连接被占住不能释放。新的请求进来,连接池里没有可用连接,只能等。如果等的时间超过超时阈值,就报超时。

怎么判断? 在数据库端看当前活跃会话,找执行时间长的 SQL。如果发现有 SQL 执行了十几秒甚至几十秒还没结束,大概率就是它占住了连接。

怎么解决? 优化慢查询(参考上一篇的方法)。同时给连接池设置合理的 maxLifetimeidleTimeout,让占住太久的连接能被强制回收。

原因 3:外部依赖慢导致连接被占用

查询本身不慢,但应用层处理逻辑慢,连接也被占住了。

场景:应用从连接池拿到连接,执行了一条 SQL(耗时 10ms),然后拿着这个连接去做外部 HTTP 调用(比如调一个第三方 API,耗时 5 秒)。在这 5 秒里,连接被占住不能还给连接池。如果有大量这样的请求,连接池很快就被耗尽。

怎么判断? 看应用层的耗时分布。如果数据库查询只占一小部分时间,大部分时间花在外部调用上,就是这个原因。

怎么解决? 缩短连接的持有时间------先做外部处理,最后再开连接、执行 SQL、立刻释放。不要拿着数据库连接做外部调用。

原因 4:数据库端限制了连接数

连接池配置没问题,但数据库本身拒绝了新连接。

MySQLmax_connections 参数限制了最大连接数。默认是 151。如果多个应用连同一个数据库实例,总连接数很容易超过这个值。

PostgreSQLmax_connections 默认是 100。

怎么判断? 在数据库端看当前连接数和最大连接数。MySQL 用 SHOW VARIABLES LIKE 'max_connections'SHOW STATUS LIKE 'Threads_connected'

怎么解决? 调大数据库的 max_connections,但要注意这会增加数据库的内存消耗。更好的方式是在应用层做连接数管控,不要让应用无限制地连数据库。


三、"连太多"排查------连接为什么泄漏

数据库报连接数打满,根因通常是连接泄漏------连接被借走了,但没有还回来。

泄漏原因 1:异常路径没有释放连接

这是最常见的连接泄漏场景。

场景:代码里从连接池拿了连接,执行 SQL,然后还回去。正常路径没问题。但如果执行 SQL 时抛了异常,异常处理逻辑里没有释放连接,这个连接就"丢"了------既不在连接池里,也不在数据库的活跃会话里(它还在,但没人管它了)。

怎么判断? 看数据库端的活跃连接数。如果连接数持续增长,但应用层的并发量没有增长,大概率是连接泄漏。

怎么解决? 确保所有代码路径都释放连接。最可靠的方式是用 try-finally 或者 try-with-resources(Java)来管理连接生命周期。不管有没有异常,finally 里一定要释放连接。

这个问题在老代码里特别常见。很多年前的代码没有考虑到异常路径的连接释放,上线时不暴露,运行几个月后连接慢慢泄漏,最终打满。

泄漏原因 2:连接池的 leak detection 没开

连接泄漏发生了,但没人知道。

HikariCP 有一个 leakDetectionThreshold 参数,用来检测连接泄漏。如果连接被借走超过这个时间还没还回来,HikariCP 会打印一条警告日志,告诉你"哪个方法拿了连接没还"。

怎么配置? 设置 leakDetectionThreshold = 60000(60 秒)。意思是如果连接被借走超过 60 秒没还,就报警。

我的习惯:生产环境这个参数一定要开。它不解决泄漏问题,但能帮你快速定位泄漏的代码位置。没有它,你只能靠猜。

泄漏原因 3:长事务持锁

连接没有泄漏,但事务开得太久,连接一直被占用。

场景:应用开启了一个事务,执行了几条 SQL,然后等着用户操作(比如在 Web 界面上等用户确认)。在用户确认之前,这个事务一直开着,连接也一直占着。如果有大量用户同时操作,连接很快就被耗尽。

怎么判断? 在数据库端看长事务。MySQL 查询 information_schema.innodb_trx,找 trx_started 时间很早但还没提交的事务。

怎么解决? 缩短事务的生命周期。事务里不要等用户操作,不要做外部调用。先把外部处理做完,最后再开事务、快速更新、立刻提交。


四、连接池配置参数------关键参数说明

不管用哪种连接池(HikariCP、Druid、或者其他),核心参数就这几个。理解了它们的含义,配置就不会出错。

核心参数

参数 含义 建议值
最大连接数 连接池里最多能有多少个连接 根据数据库能力和并发量综合评估,一般 20-100
最小空闲连接数 连接池里至少保持多少个空闲连接 一般设为最大连接数的一半左右
连接超时时间 从连接池借连接时,最多等多久 3-10 秒。太短了容易误报,太长了用户等不起
连接最大生命周期 连接创建后最多存活多久 比数据库的 wait_timeout 短一些,避免拿到过期连接
空闲超时时间 空闲连接多久没被使用就回收 10-30 分钟。太长浪费资源,太短频繁创建销毁

配置建议

  1. 最大连接数不要设太大。一个数据库实例能高效支撑的连接数是有限的。设太大反而会导致连接争用和上下文切换开销。
  2. 连接超时时间设合理。3-10 秒是比较合理的范围。设成 30 秒或 60 秒的话,用户等不了那么久。
  3. 最大生命周期一定要设。很多连接池默认不设置这个参数,导致连接一直不回收。如果数据库端有超时断开机制(比如 MySQL 的 wait_timeout),连接池里的连接可能会拿到已经断开的连接。
  4. 开启泄漏检测。生产环境务必开启,阈值设 60 秒左右。

五、连接池监控------日常巡检清单

连接池问题最好的处理方式是在出问题之前发现。以下是日常巡检要点:

  1. 看连接使用率。活跃连接数占总连接数的比例。如果长期超过 80%,说明连接池偏小了。
  2. 看等待队列长度。如果有请求在排队等连接,说明连接不够了。
  3. 看连接创建/销毁频率。如果频繁创建和销毁连接,说明连接池大小不合适或者泄漏了。
  4. 看连接获取耗时。正常情况下应该是毫秒级。如果出现秒级的获取耗时,说明连接池快满了。
  5. 看数据库端连接数。和连接池的活跃连接数对比,如果有明显差异,可能有泄漏。

六、总结

连接池排查就两个方向:连不上看容量和慢查询,连太多看泄漏和长事务

连接池配置的核心原则是:够用就好,不要贪大。连接数太大反而会带来性能问题。

预防连接问题的关键是:泄漏检测要开、事务要短、监控要看

处理过上百次连接池问题,每次回到这套流程,问题都能解决。不需要什么高级工具,耐心和方法论就够了。

下一篇我会讲数据库备份恢复实战,把运维高频问题系列收个尾。

有问题评论区见。


十五年数据库领域老炮。关注我,一起把数据库这件事搞明白。

相关推荐
一只专注api接口开发的技术猿2 小时前
电商评论自动化监控与情感数据分析完整落地教程(附可直接运行 Python 代码)
大数据·数据库·python·数据分析·自动化
hh真是个慢性子2 小时前
GaussDB Inside 2.23.01.280 集中式一主一备安装
数据库·database·gaussdb·国产数据库·高斯
沉静的小伙2 小时前
Spring事务
java·数据库·spring
大侠锅锅2 小时前
第 3 篇:节点自动化纳管——从裸机到可管理的 7 步安装流水线
数据库·自动化·边缘计算·iot
笃行3502 小时前
踩坑实战 | MySQL/PostgreSQL 迁移必踩:LEFT JOIN 莫名丢数据,KES 外连接消除避坑指南
数据库
摇滚侠2 小时前
Redis7 零基础到进阶 Linux 离线安装 Redis 09-10
数据库·redis·缓存
赵渝强老师3 小时前
【赵渝强老师】达梦数据库的回滚数据
数据库·达梦数据库·国产数据库
从此以后自律3 小时前
SQL 语句从基础到高级
数据库·oracle
IvorySQL3 小时前
PG 日报|多款 PostgreSQL 工具新版本集中发布
数据库·postgresql