mysql连接池配置与高并发请求的优化方案

来源:这里教程网 时间:2026-02-28 20:49:15 作者:

MySQL 连接池最大连接数设多少才不翻车

盲目调高

max_connections
不但不能提升吞吐,反而会因线程竞争、内存耗尽导致 MySQL 崩溃。真实压测中,多数业务在
200–500
之间就遇到瓶颈,关键不在“能开多少”,而在“有多少连接真正在干活”。

先查当前活跃连接:
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Threads_running';
—— 后者才是正在执行 SQL 的线程,它长期 > 50 就说明查询慢或锁等待严重
应用层连接池(如 HikariCP)的
maximumPoolSize
建议设为 DBA 允许的
max_connections
的 60%~70%,留出空间给后台任务、监控、DBA 操作
MySQL 服务端的
max_connections
不建议超过
1000
(尤其在 8GB 内存以下机器),每连接默认占用约 2MB 内存,超了直接 OOM

HikariCP 关键参数怎么配才不拖慢请求

HikariCP 不是设了

maximumPoolSize
就万事大吉,几个隐藏坑点常让高并发下连接获取超时或空转。

connectionTimeout
必须显式设(如
3000
),否则默认 30 秒——用户等半分钟才报错,体验极差
idleTimeout
建议设为
600000
(10 分钟),太短会导致频繁销毁重建连接;但若后端 MySQL 开了
wait_timeout=60
,必须让
idleTimeout
小于它,否则连接被服务端主动断开后,HikariCP 不知道,下次取出来直接报
Connection closed
leakDetectionThreshold
设成
60000
(60 秒),能抓到没 close() 的 Connection,避免连接泄露把池子占满
禁用
testOnBorrow
(已废弃),改用
connectionTestQuery=SELECT 1
+
validationTimeout=3000
,避免每次取连接都执行校验拖慢响应

事务边界不清导致连接池卡死的真实案例

高并发下最常见“连接池耗尽”不是因为 QPS 高,而是事务没及时结束,连接被长期占用。典型表现:

Threads_running
低,但 HikariCP 的
active
连接数持续接近
maximumPoolSize
,且
pending
队列不断增长。

Spring Boot 中 @Transactional 注解方法若抛出非 RuntimeException(如 checked exception),事务默认不回滚,连接也不会释放——务必确认
@Transactional(rollbackFor = Exception.class)
流式查询(
ResultSet.TYPE_FORWARD_ONLY
)未关闭
ResultSet
Statement
,连接无法归还,HikariCP 日志会出现
Connection marked as broken because of an exception
异步任务(@Async)里开启事务,容易脱离原始请求生命周期,连接在异步线程结束后才释放,造成“连接幽灵占用”

读写分离 + 连接池分组的实际落地要点

单主多从架构下,把所有流量打向主库,连接池再优化也扛不住写请求激增。分组连接池不是简单配两个 HikariDataSource,而是要和路由逻辑对齐。

主库连接池
maximumPoolSize
可设小些(如 30),从库池可稍大(如 80),因为读请求通常更多、更轻量
避免在 DAO 层硬编码
slaveDataSource
,用 AbstractRoutingDataSource + ThreadLocal 路由,但注意 Spring 的事务传播机制:如果一个 @Transactional 方法里先查后写,必须强制走主库,否则从库查到的是旧数据
从库延迟监控必须做——当
Seconds_Behind_Master > 30
时,自动将该从库连接池
setIsReadOnly(false)
或临时剔除,否则读到脏数据比慢还致命
连接池不是越大越好,也不是配完就稳。真正卡住系统的,往往是那个忘了关 ResultSet 的 for 循环,或是事务传播类型写错的 @Transactional 方法。盯住
Threads_running
和 HikariCP 的
active
/
pending
指标,比背参数重要得多。

相关推荐