Oracle连接池配置实战------社保系统从20连接到200连接的血泪史
连接池不是设个数字就完了。20个连接够用的系统,接了更多下游后突然全线超时。这篇文章从社保系统的真实案例出发,拆开HikariCP连接池的配置策略------不是调参数,是找根因。
文章目录
- Oracle连接池配置实战------社保系统从20连接到200连接的血泪史
-
- 一、从20到200------不是放大就管用
- [二、HikariCP 核心参数](#二、HikariCP 核心参数)
- 三、连接泄漏------最隐蔽的问题
- 四、连接池太大也不行------数据库侧撑不住
- 五、连接有效性校验------别每次借出都查
- 六、最终配置
一、从20到200------不是放大就管用
社保系统最初使用HikariCP,连接池设了20。单体应用,几个接口,20个连接绰绰有余。
后来接了省平台数据交换、银行扣款回调、养老金发放查询------一个接口进来要同时查3-4个下游。高峰期30人同时操作,每人触发一个接口,每个接口需要2-3个数据库连接------瞬间需要60-90个连接,而池子只有20个。
结果不是"第7个人被拒绝"------是所有请求都在队列里等连接。等一个连接释放,后面的请求已经超时。前端白屏。
二、HikariCP 核心参数
yaml
spring:
datasource:
hikari:
minimum-idle: 10 # 最小空闲连接,池初始化时就创建
maximum-pool-size: 50 # 最大连接数(含空闲+使用中)
idle-timeout: 600000 # 空闲超时(10分钟),超过则回收
max-lifetime: 1800000 # 连接最大生存时间(30分钟),超时强制回收
connection-timeout: 30000 # 等待连接的超时时间(30秒)
validation-timeout: 5000 # 连接校验超时
leak-detection-threshold: 60000 # 连接泄漏检测(60秒未归还则告警)
关键是理解三个超时的关系:
连接生命周期:
创建 → 借出(使用中) → 归还(空闲) → 空闲超时回收
| | |
| leak-detection idle-timeout
| (60s告警) (10min回收)
|
max-lifetime (30min强制回收)
三、连接泄漏------最隐蔽的问题
社保系统曾经出现过这样的现象:每天早上正常,下午变慢,第二天又恢复。
日志里没有报错,JVM内存正常,但 hikaricp - connection is not available, request timed out after 30000ms 间歇性出现。
用 leak-detection-threshold=60000 打开后,日志开始输出:
HikariPool-1 - Connection leak detection triggered for connXX,
stack trace follows
java.lang.Exception: Apparent connection leak detected
at com.zaxxer.hikari.HikariDataSource.getConnection
at com.browise.service.PersonService.query(PersonService.java:156)
...
问题定位到 PersonService.query------某个异常分支里 try-with-resources 没有正确关闭 ResultSet,连接被吃掉了但没归还。问题发生频率每天下午高是因为下午查询量大,泄漏累积到连接池耗尽。
修法:所有数据库操作统一走 JdbcTemplate 或 @Transactional,不在业务代码里手动管理连接。
四、连接池太大也不行------数据库侧撑不住
把连接池从20调到200后,系统确实不超时了------但Oracle数据库开始报 ORA-00020: maximum number of processes exceeded。
Oracle 的 processes 参数限制了同时连接的总进程数。默认是150-300。200个HikariCP连接 + 50个其他应用连接 = 250,刚好超过。
改法不是调大连接池------是减少每个请求的连接数:
java
// 改前:一个请求打开3次连接
Connection c1 = ds.getConnection(); // 查密码
Connection c2 = ds.getConnection(); // 查状态
Connection c3 = ds.getConnection(); // 查权限
// 改后:一次连接完成所有查询
Connection c = ds.getConnection();
// 查密码、状态、权限全部在同一连接上执行
同时调整Oracle:
sql
ALTER SYSTEM SET processes=500 SCOPE=SPFILE;
-- 重启生效
五、连接有效性校验------别每次借出都查
很多教程让配 connection-test-query: SELECT 1 FROM DUAL。HikariCP默认不 需要这个------它有更高效的 isValid() 检查。
如果一定要配,不要配在借出时校验:
yaml
# 正确:只在空闲超时回收前校验
hikari:
keepalive-time: 30000 # 每30秒心跳保活
# 不配 connection-test-query ------ 让HikariCP用自己的isValid
只有当Oracle配置了防火墙超时断开空闲连接(如DCD/死连接检测),才需要 keepalive-time。平时不用。
六、最终配置
yaml
spring:
datasource:
hikari:
minimum-idle: 5
maximum-pool-size: 40 # 并发×每请求连接数,加20%余量
idle-timeout: 300000
max-lifetime: 600000
connection-timeout: 10000 # 10秒拿不到就报错,别让用户等
leak-detection-threshold: 30000 # 30秒未归还告警
keepalive-time: 60000 # 防火墙有超时断开机制时才配
核心原则:
- 最大连接数不是越大越好------先算并发请求×每请求连接数,再加20%
- 先查连接泄漏,再调连接池大小------80%的超时是泄漏导致的
- 减少每请求连接数比增大池子更有效------合并查询到同一个Connection
- leak-detection-threshold 是必开项------生产环境不开这个等于盲飞
✅ 亮点:从社保系统真实案例出发,从问题现象一路定位到根因(连接泄漏),用日志输出直接定位到出问题的代码行。扩展方向:Druid vs HikariCP对比、PolarDB/OceanBase连接池适配。