连接池核心参数:最小空闲连接数、最大连接数、连接超时时间
连接池调优,说白了就是跟三个数字打交道:最小空闲连接数、最大连接数、连接超时时间。这三个参数就像发动机的油门、刹车和限速器——调得好,系统丝滑;调不好,要么卡死,要么浪费资源。
我个人习惯先把它们拆开理解,再合起来看联动关系。咱们一个一个说。
最小空闲连接数(minimumIdle)
这个参数控制连接池“闲时”保留多少连接。比如设成5,那不管有没有请求,池子里至少躺着5个可用连接。好处是——突然来流量时不用现场创建连接,直接拿现成的,响应快。
但别设太大。我在项目中遇到过一个小型后台服务,minimumIdle 设了50,结果服务刚启动就一口气创建50个连接。数据库那边直接报警了——你想想看,一个平时只有20并发的小应用,让50个连接占着坑,那不是浪费么?
minimumIdle 设成 maximumPoolSize 的 20%~30% 就够了。突发流量多的场景,可以适当提高到 40%,但不要超过一半。
最大连接数(maximumPoolSize)
这个参数就是连接池的“天花板”。池子里能同时存在的连接数不能超过这个值。设小了,请求排队;设大了,数据库扛不住。
我记得有一次帮朋友优化一个电商订单系统。他们数据库是 4 核 8G 的 MySQL,连接池最大连接数直接拉了 200。上线没两天,数据库 CPU 跑满,慢查询一堆。我一看配置就知道出事了——MySQL 的默认连接数是 151,你把池子开到 200,数据库本身还有后台线程、复制线程,实际能用的连接数远少于理论值。
| 数据库规格 | 建议最大连接数 | 备注 |
|---|---|---|
| 4核8G MySQL | 30~60 | 不超过数据库 max_connections 的 60% |
| 8核16G MySQL | 50~120 | 按连接平均消耗 2~3MB 算 |
| 2核4G PostgreSQL | 20~40 | PG 每个连接开销更大 |
你可能会问:那怎么算才准?我建议用这个简单公式:最大连接数 = (数据库 CPU 核心数 × 2) + 预留缓冲。预留缓冲通常加 10~20 就够,别搞太大。
maximumPoolSize 设了 80,但应用实际并发只有 10 左右。结果就是连接池里 70 个连接常年闲着,占着数据库的连接配额,导致其他服务连不上。你想想看,浪费钱不说,还制造故障。
连接超时时间(connectionTimeout)
这个参数定义了:等一个连接最多等多久。如果池子里没有空闲连接了,请求线程会阻塞。超过这个时间,就抛异常。
设太短,比如 1 秒,流量波峰时大量请求被直接拒绝,用户体验极差。设太长,比如 60 秒,线程会一直卡在那边,拖慢整个应用。
我以前在支付系统里遇到过一个问题:connectionTimeout 设了 30 秒,结果某次数据库主从切换时,所有获取连接的线程都阻塞在那 30 秒,Tomcat 线程池被占满,整个服务变成“假死”。
// HikariCP 配置示例
HikariConfig config = new HikariConfig();
config.setMinimumIdle(10);
config.setMaximumPoolSize(50);
config.setConnectionTimeout(5000); // 毫秒,推荐 3~10 秒
config.setIdleTimeout(600000); // 10分钟
config.setMaxLifetime(1800000); // 30分钟
三个参数如何协同工作
这三个参数不是孤立的。它们构成一个动态平衡系统:minimumIdle 决定了“保底库存”,maximumPoolSize 划定了“上限”,connectionTimeout 控制了“等待耐心”。当请求量超过 minimumIdle 时,池子会动态创建新连接,直到到达 maximumPoolSize。如果继续超载,请求就进入等待队列,直到超过 connectionTimeout 才抛出异常。
核心要点:
minimumIdle不要超过maximumPoolSize的 40%,否则浪费。maximumPoolSize要参考数据库规格,别凭感觉设。connectionTimeout建议 3~8 秒,别让线程死等。- 三个参数联动:空闲不够→创建→触顶→等待→超时。
调优小技巧:先压测,看平均响应时间和并发峰值。比如压测时平均 50 并发,那就把 minimumIdle 设 15~20,maximumPoolSize 设 60~80。再观察数据库 CPU 和连接数,微调两三回就能找到最佳点。
常见陷阱:
- 陷阱一:
maximumPoolSize设得比数据库max_connections还大,直接连不上。 - 陷阱二:
connectionTimeout设成 0(表示无限等待),系统扛不住突发流量时会一直阻塞,最终 OOM。 - 陷阱三:
minimumIdle和maximumPoolSize设成一样,等同禁止扩容,失去了连接池的意义。