连接池耗尽导致请求变慢,是因为新请求进入等待队列而非立即失败,线程被阻塞直至connection-timeout超时,表现为“timeout waiting for available connection”,而mysql端可能仅显示少量活跃连接和大量sleep连接。

连接池配置不合理是导致MySQL响应延迟的最常见原因,不是数据库本身慢,而是连接卡在排队或泄漏上。
为什么连接池耗尽会让请求变慢?
当连接池满时,新请求不会立刻失败,而是进入等待队列。只要 connection-timeout 没到,它就一直卡着线程等——这直接拖垮应用吞吐量,且错误日志里看不到“Too many connections”,只有超时或线程阻塞痕迹。
- Java 应用里常表现为
timeout waiting for available connection,但 MySQL 的show processlist可能只看到几个活跃连接,大量 Sleep 连接被漏掉 - PHP 用
mysql_pconnect()或 FPM 子进程复用连接时,Sleep 连接堆积更快,wait_timeout默认 28800 秒(8 小时),等于放任连接长期占坑 - Go 的
sql.DB若没设SetMaxOpenConns,默认不限制,容易打爆 MySQL 的max_connections
HikariCP 关键参数怎么设才不踩坑?
别照搬示例值,重点看三个参数之间的咬合关系:池大小、空闲回收、连接寿命必须协同,否则一个调错,其他全失效。
-
maximumPoolSize:设为 MySQLmax_connections的 60%~70%,例如 MySQL 是 500,这里最多设 350;超过这个数,新连接会被 MySQL 直接拒绝,池再大也没用 -
idleTimeout:建议 600000(10 分钟),比 MySQL 的wait_timeout小;如果 MySQL 设了 60 秒,而池子还让连接活 30 分钟,归还后立刻变 Sleep,白忙一场 -
maxLifetime:设 1800000(30 分钟)比默认的 30 分钟更稳妥,避免连接因中间网络设备(如 NAT、LB)静默断连后仍被复用
如何验证连接真的被正确释放?
光看代码里有没有 close() 不够,得看运行时行为。很多泄漏发生在 finally 块漏写、或用了 try-with-resources 却没 catch 所有异常分支。
- 开启 HikariCP 的
leak-detection-threshold=60000(毫秒),它会在连接被借用超 60 秒未归还时打印堆栈,精准定位泄漏点 - 在 MySQL 端执行:
SELECT * FROM information_schema.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 300,查出空闲超 5 分钟的连接,手动KILL并反查对应应用日志 - 用
SHOW STATUS LIKE 'Threads_%'对比Threads_connected和Threads_running,如果前者远大于后者,说明大量连接挂起没干活
最容易被忽略的是连接池和 MySQL 两端超时参数的倒挂——比如池子等连接 30 秒,MySQL 却在 10 秒后就把空闲连接踢了,结果池子还在傻等,应用线程就卡死了。











