连接池核心参数详解

连接池的配置,说白了就是一堆数字的博弈。我刚入行那会儿,觉得连接池无非就是设个最大连接数,够用就行。结果线上一次故障让我彻底改了想法——连接池的参数,每一个都藏着坑,调不对就是事故。

这节课,我把几个最关键的参数掰开揉碎讲清楚。你以后配置连接池,心里就有底了。

核心参数全景

先来看一张图。这张图把连接池的核心参数串起来了,你一眼就能看出各参数之间的关系。

连接池核心参数关系图 连接池核心参数全景 容量参数 时间参数 校验参数 maximumPoolSize 最大连接数 minimumIdle 最小空闲连接数 maxPoolSize 池中最大连接数 initialPoolSize 初始连接数 connectionTimeout 连接超时(毫秒) idleTimeout 空闲超时 maxLifetime 最大存活时间 keepaliveTime 保活间隔 validationTimeout connectionTestQuery 连接测试SQL testOnBorrow 获取时校验 testOnReturn 归还时校验 testWhileIdle 空闲时校验 依赖 决定

这张图把参数分成三组:容量参数、时间参数、校验参数。下面我逐个拆解。

最大连接数(maximumPoolSize)

这是最核心的参数,没有之一。它决定了连接池里最多能有多少个连接同时工作。

核心原则:最大连接数不是越大越好!

为什么这么说?我在一个高并发项目里遇到过,团队把最大连接数设成了 500,结果数据库直接被压垮,CPU 飙到 100%。

你想想看,数据库处理连接是有成本的。一个连接对应一个数据库进程或线程,太多连接会导致上下文切换频繁、锁竞争加剧,最后吞吐量反而下降。

那设置多大合适?我建议用这个公式估算:

最大连接数 = (核数 * 2) + 有效磁盘数

这是一个经典公式。举个例子:一个 8 核服务器,SSD 磁盘(有效磁盘数算 1),那初始值就是 (8*2)+1=17 个连接。然后再根据实际压力测试上下调整。

应用场景 参考值 说明
低并发应用 5-10 后台管理、报表系统
中等并发应用 10-30 一般Web服务
高并发应用 30-50 电商核心、实时系统
极高并发应用 50-200 需配合数据库优化

避坑指南:我曾经见过一个团队把最大连接数设成 1000,结果数据库连接池满了后,应用直接 OOM。因为每个连接都要消耗内存和文件描述符,连接数过大,操作系统先扛不住。

最小空闲连接数(minimumIdle)

这个参数控制连接池里至少保持多少个空闲连接。它的作用就是应对突发流量。

我个人习惯把 minimumIdle 设成和 maximumPoolSize 一样。这样系统启动后就会把连接全部创建好,流量来了直接复用,不会有创建连接的开销。

但这种方式也有代价——连接是空闲的,数据库那边却要一直维护它。如果服务 QPS 很低,就会浪费资源。

所以,这里有个权衡:

  • 追求响应速度:minimumIdle 设大一点,最好等于 maximumPoolSize
  • 追求资源节约:minimumIdle 设小一点,比如 2-5 个
  • 折中方案:minimumIdle = maximumPoolSize / 2

小技巧:如果服务要求启动快,别把 minimumIdle 设太大。否则启动时要创建大量连接,反而拖慢启动速度。可以先设一个较小的 initialPoolSize,等流量上来后让连接池自动扩容。

连接超时(connectionTimeout)

这个参数的意思是:应用从连接池里拿连接时,最多愿意等多久。等不到就抛异常。

超时时间太短,系统很容易误报故障。太长呢,用户就在那里傻等着,体验极差。

我处理过一个案例:一个团队把 connectionTimeout 设成了 500 毫秒。数据库偶尔抖动一下,应用就报连接获取超时,整条链路都在报错。后来我们改成 5 秒,抖动时系统就扛过去了。

场景 推荐值 理由
快速失败 1-3 秒 对延迟敏感,宁可失败也不等待
常规服务 3-5 秒 兼顾响应与可用性
慢查询场景 5-15 秒 数据库处理本身就慢,多给点时间

注意:connectionTimeout 只控制“从池中获取连接”的等待时间,不控制 SQL 执行时间。SQL 执行时间超时要用 statementTimeout。

连接存活时间(maxLifetime)

每个连接在池子里待久了,就可能被数据库那边断开。比如 MySQL 的 wait_timeout 默认 8 小时,如果你不设 maxLifetime,连接就会变成一个坏连接,但应用不知道。

我个人建议 maxLifetime 设成小于数据库的 wait_timeout。比如数据库 wait_timeout 是 30 分钟,那 maxLifetime 就设 25 分钟。这样在数据库断开之前,连接池主动把连接淘汰掉,换新的。

// HikariCP 推荐配置示例
spring.datasource.hikari.maxLifetime=1800000  // 30分钟

注意:maxLifetime 不能设得太短,否则连接频繁被换掉,造成不必要的创建开销。一般 15-30 分钟是比较合理的区间。

空闲超时(idleTimeout)

如果一个连接空闲太久了,连接池会把它关掉,释放资源。这个参数只在 minimumIdle 小于 maximumPoolSize 时有意义。

为什么?因为如果 minimumIdle 等于 maximumPoolSize,空闲连接数是固定的,永远不会有“多余的空闲连接”,idleTimeout 就没用。

我通常把 idleTimeout 设为 maxLifetime 的一半。比如 maxLifetime 是 30 分钟,idleTimeout 就设 15 分钟。这样空闲连接不会一直占着资源,又能应对突发的小流量。

spring.datasource.hikari.idleTimeout=600000  // 10分钟

连接校验参数

这几个参数决定连接池怎么判断一个连接是不是好的。坏连接千万别发给应用,否则就是一堆 SQLException。

  • testOnBorrow:拿连接时校验。最严格,但每次拿连接都有开销
  • testOnReturn:归还时校验。能保证还回来的连接是好的
  • testWhileIdle:后台线程定时校验。不影响业务线程,推荐

对于高性能场景,我建议关闭 testOnBorrow 和 testOnReturn,只开 testWhileIdle。坏连接被后台线程发现后直接淘汰,下次拿到的都是好连接,不会有性能损耗。

最佳实践:高性能场景推荐方案

testOnBorrow = false
testOnReturn = false
testWhileIdle = true
validationQuery = SELECT 1

参数调优的黄金法则

说了这么多,我最后给你几条铁律。这些是我踩过坑后总结出来的:

  1. 先压测,再调参。没有压力测试数据,所有参数都是猜的
  2. 一次只改一个参数。改了连接数又改超时时间,出了问题你根本不知道是谁的锅
  3. 监控连接池状态。看活跃连接数、空闲连接数、等待获取连接的线程数,这些数据比参数本身更值钱
  4. 参数要和业务匹配。读多写少的服务和写多读少的服务,参数配置完全不同

我参与过一个项目,上线前把所有连接池参数都翻了一遍,全部按理论值设好。结果上线后压测直接就挂了。后来我们把所有参数调回默认值,只改了一个 maxPoolSize,反而好了。所以记住:默认值通常是最好的起步点。

调参是一场持续的优化过程。你不可能一次就找到最佳值。把监控做好,有了数据支撑,再慢慢调整,那才是正确的路子。