连接池大小应基于平均连接持有时间与数据库并发上限计算,而非简单匹配QPS;例如QPS=200、平均持有150ms,理论需30个连接,加30%缓冲设为40更合理,盲目设200易致资源争抢或连接耗尽。

连接池大小不是 QPS 的简单复制
很多人一看到应用 QPS 是 200,就直接把 maximumPoolSize 设成 200——这几乎必然导致数据库端资源争抢或连接耗尽。真正起决定作用的是“连接平均持有时间”和“数据库并发处理上限”。比如一个请求平均占连接 150ms,QPS=200,理论需 30 个连接(200 × 0.15),再加 30% 缓冲,设 maximumPoolSize=40 就比设 200 更稳。
常见错误现象:Too many connections 报错频发,但 SHOW STATUS LIKE 'Threads_running' 峰值却只有 10–15;说明连接被长期占用(如慢查询、事务未提交、连接未归还),而非并发真高。
- 先查数据库真实负载:运行
SHOW STATUS LIKE 'Threads_connected'观察 15 分钟以上峰值,再对比SHOW VARIABLES LIKE 'max_connections' - 应用侧总连接上限 = 单实例
maximumPoolSize× 实例数 + 预留 buffer(建议 +50~100) - 若数据库是 4 核机器,
max_connections设到 500 已属偏高,对应应用侧所有实例的maximumPoolSize总和应控制在 350 以内
HikariCP 的 minIdle 和 initialSize 别乱设
现代连接池(如 HikariCP)默认不设 minIdle,靠 idleTimeout 自动回收空闲连接。硬设 minIdle 只在有明显波峰波谷的场景下有意义,比如夜间流量跌到 5 QPS,白天冲到 150 QPS。
容易踩的坑:minIdle 设得太高(比如等于 maximumPoolSize),低峰期大量连接空转,既占内存又干扰监控判断;设得太低(如 0),冷启动后前几批请求会因建连延迟明显变慢。
-
initialSize建议等于minIdle,避免启动后首次查询卡顿 - 若设了
minIdle,推荐为maximumPoolSize的 10%~20%,例如maximumPoolSize=40→minIdle=4~8 - 不设
minIdle时,确保idleTimeout合理(通常 600000ms 即 10 分钟),否则空闲连接无法及时释放
超时与验证必须配对生效
只设 maximumPoolSize 不配超时,连接池可能卡死在等一个永远回不来的连接上;只做超时不验证,拿到的可能是 MySQL 已断开的“僵尸连接”,后续执行 SQL 直接报 Communications link failure。
关键参数要联动:connectionTimeout(获取连接超时)、validationTimeout(验证超时)、keepaliveTime(保活间隔)三者必须协调。MySQL 的 wait_timeout 默认 8 小时,但生产环境常调为 30 分钟,所以连接池的 maxLifetime 必须小于它(建议设 1800000ms 即 30 分钟)。
-
connectionTimeout推荐 30000ms(30 秒),太短易误判,太长拖慢整个请求链路 - 验证语句用
SELECT 1,不要用mysql_ping()(部分驱动不支持) -
validationTimeout必须 ≤connectionTimeout,且建议 ≤ 5000ms,避免验证本身成为瓶颈
thread_pool_size 在社区版根本不存在
很多文档写着“调大 thread_pool_size 解决高并发”,但 MySQL 社区版(5.7/8.0)压根不支持该参数。试图执行 SET GLOBAL thread_pool_size = 16 或配置文件里写入,只会报错 Unknown system variable 'thread_pool_size'。
真正可用的替代是 thread_cache_size:它缓存空闲线程供新连接复用。这个值不是越大越好,过高反而增加线程管理开销。
- 查当前活跃线程数:
SHOW STATUS LIKE 'Threads_created',若每秒递增快,说明缓存不够 -
thread_cache_size推荐设为ceil(max_connections / 16),但上限一般不超过 16 - 如果确实需要线程池能力,必须换 Percona Server 或 MySQL Enterprise,并确认插件已加载:
INSTALL PLUGIN thread_pool SONAME 'thread_pool.so'
connection.close() 或没正确释放事务,Threads_connected 就会持续上涨直至打满。与其反复调 maximumPoolSize,不如先用 AOP 或代理机制兜底检查连接泄漏。


















