易君召
发布于 2026-09-05 / 作者:易君召 / 6 阅读
0

数据库连接常见性能问题理解

数据库连接本质是客户端与数据库之间的会话通道,建立连接是重操作(TCP 三次握手、身份认证、权限加载、初始化会话上下文),不能频繁创建销毁,大部分连接性能问题都围绕:连接创建开销、连接泄漏、连接池配置不合理、长连接 / 短连接误用、网络、事务持有连接这几大块。

1. 频繁创建销毁连接(短连接滥用)

现象

每次执行 SQL 都新建连接,用完直接关闭,不使用连接池。

  • 高并发下大量时间消耗在TCP握手、认证、权限初始化,CPU 大量消耗在数据库侧处理连接握手。

  • 数据库服务器processlist瞬间大量连接进来又消失,端口大量 TIME_WAIT。

根源

没有连接池,每次业务请求:新建连接→执行 SQL→close。

危害

QPS 稍微上来,数据库就被建连接压垮,SQL 本身很快,但整体响应很慢。

解决

必须使用连接池复用连接,不要裸用短连接。

2. 连接泄漏(最常见线上故障)

拿到连接,没有归还回连接池

现象

  1. 连接池活跃连接数持续上涨,不回落,最终打满最大连接数;

  2. 新请求拿不到连接,报:cannot get connection from pool

  3. 数据库侧看到大量 sleep 空闲连接。

泄漏常见场景

  1. 代码异常,没有finally关闭 / 归还连接;老 JDBC 手动写 Connection,异常分支没 close;

  2. 事务卡住:开启事务之后,异常没有回滚 / 提交,连接一直被事务占有;

  3. 框架错误:部分框架异常场景不自动归还连接;

  4. 调用外部接口、RPC 的时候,事务内做耗时 IO,连接被长时间占用。

重点误区:不是 SQL 慢叫泄漏,是连接拿出去之后永不归还。

排查

监控连接池指标:活跃连接、空闲连接、等待队列长度。活跃只涨不降基本就是泄漏。

3. 连接池参数配置错误(线上重灾区)

以 HikariCP、Druid 为例,几个核心参数:

参数

错误配置

后果

maximumPoolSize 最大连接

设置过大,比如 1000

数据库侧连接数打满,上下文切换、锁竞争加剧,数据库性能雪崩

maximumPoolSize 设置过小

并发请求多,连接不够用,大量业务线程排队等待获取连接

idleTimeout 空闲连接超时

太长,大量空闲连接占数据库连接数;太短,连接频繁销毁重建

connectionTimeout 获取连接超时

设置过小,高并发直接大量报错拿不到连接;过大,请求堆积

maxLifetime 连接最大生命周期

大于数据库 wait_timeout,拿到已经被数据库断开的无效连接,报异常

核心认知:连接池最大连接不是越大越好。数据库 CPU、锁、buffer 有限,MySQL 单实例通常 maxPoolSize 几十就足够,不是几百上千。 公式参考:最大连接数 ≈ CPU核心数 * 2 + 磁盘数,业务有慢 SQL 可适当调大,严禁无脑上千。

4. 长连接 vs 短连接误用

  • 长连接(连接池):连接建立后一直复用。优点:省去建连开销;风险:连接会被数据库端 kill(wait_timeout),出现 “死连接”,应用拿到已经断开的连接执行 SQL 报错。 👉 连接池必须配置maxLifetime小于数据库wait_timeout,定期淘汰旧连接。

  • 短连接:用完立刻关闭。适合低频小并发;高并发绝对禁止,会打满 TIME_WAIT,数据库扛不住建连压力。

常见坑:MySQL 设置wait_timeout=8小时,连接池 maxLifetime 没配置,8 小时后池子里全是僵尸连接。

5. 连接被慢事务 / 慢 SQL 长时间占用

连接池连接总数有限,如果一个连接被占住不释放,其他业务就要排队等连接。

现象

连接池活跃连接打满,但没有泄漏;看数据库:大量事务长时间运行,Sleep或者正在执行慢 SQL。 场景:

  1. 事务里面写大量业务逻辑、HTTP 调用、RPC、循环大计算;事务没提交,连接死死占用。

  2. 慢 SQL 执行几十秒,连接被占用。 后果:业务线程全部阻塞在获取数据库连接,整个服务雪崩,不是数据库挂,是应用拿不到连接

重要:连接池耗尽 ≠ 数据库 CPU 高。很多时候数据库负载很低,但应用全部超时,根源就是连接被长事务占死。

6. 网络层面带来的连接问题

  1. 防火墙、NAT 超时:中间网络设备空闲超时,静默断开 TCP 连接,应用不知情,池子里存在僵尸连接。

  2. 网络抖动:丢包,连接半开状态。 解决:连接池的连接检测(testOnBorrow /testWhileIdle),定期校验连接可用性。

testOnBorrow 每次拿连接都校验性能差,生产推荐testWhileIdle

7. 数据库侧最大连接数限制

MySQL max_connections参数,数据库全局允许最大会话。

  • 应用连接池总和超过数据库 max_connections → 数据库拒绝新连接,报Too many connections

  • 很多人只调应用连接池,忘记数据库侧上限。

max_connections 不是越大越好,连接过多内存、锁上下文开销暴涨。

8. 经典故障区分,快速定位

  1. 报错:获取连接超时

    • 看连接池活跃连接:打满。

      • 活跃连接不下降:连接泄漏 OR 长事务 / 慢 SQL 占住连接。

      • 活跃连接没打满:并发太高,maxPoolSize 设置太小。

  2. 偶发 SQL 报错,通信链路失败:大概率僵尸连接,maxLifetime 配置不对,NAT 防火墙断开空闲连接。

  3. 数据库大量新建连接,TIME_WAIT 高:没有连接池,短连接模式。

简单总结记忆

  1. 创建连接很重,所以要用连接池复用连接

  2. 连接池两个杀手:连接泄漏长事务占用连接

  3. 连接池不是越大越好,maxPoolSize 要和数据库能力匹配;

  4. 长连接会变成僵尸连接,池子里要设置连接过期时间,小于数据库 wait_timeout;

  5. 事务里不要做远程调用、耗时逻辑,连接会被霸占;

  6. 监控指标:活跃连接数、空闲连接、获取连接等待队列、数据库当前连接数。


本文原创作者:易君召,详见:https://www.yijunzhao.cn/authors/yijunzhao,转载请注明出处。

原文链接 https://www.yijunzhao.cn/archives/database-connection-common-performance-issues-guide

欢迎访问 小易撩挨踢

https://www.yijunzhao.cn/