先看看 Druid 的 maxEvictableIdleTimeMillis 是啥?
DestroyTask 线程销毁任务每隔 timeBetweenEvictionRunsMillis (默认一分钟)的时间会执行一次连接池瘦身检测 DruidDataSource#shrink(checkTime:true, keepAlive);
if (idleMillis >= minEvictableIdleTimeMillis) {
if (checkTime && i < checkCount) { // checkCount = poolingCount - minIdle
evictConnections[evictCount++] = connection;
continue;
} else if (idleMillis > maxEvictableIdleTimeMillis) {
evictConnections[evictCount++] = connection;
continue;
}
}
checkTime = true 所以会再判断 i < checkCount
是否成立,而 checkCount = poolingCount - minIdle 也就是超过 minIdle 那部分连接(类似线程池的 maximumPoolSize - corePoolSize )
所以,代码逻辑是 1~minIdle 的连接空闲超过 maxEvictableIdleTimeMillis(默认7小时) 则需要清除掉, minEvictableIdleTimeMillis(默认30分钟) 针对的是超过 minIdle 的那部分连接
maxEvictableIdleTimeMillis 表示的是 minIdle 内连接能空闲的最大时长
hikariCP 的 maxLifetime
HikariPool#createPoolEntry 创建连接池条目
final long maxLifetime = config.getMaxLifetime();
if (maxLifetime > 0) {
// variance up to 2.5% of the maxlifetime
final long variance = maxLifetime > 10_000 ? ThreadLocalRandom.current().nextLong( maxLifetime / 40 ) : 0;
final long lifetime = maxLifetime - variance;
poolEntry.setFutureEol(houseKeepingExecutorService.schedule(
() -> {
if (softEvictConnection(poolEntry, "(connection has passed maxLifetime)", false /* not owner */)) {
addBagItem(connectionBag.getWaitingThreadCount());
}
},
lifetime, MILLISECONDS));
}
hikari在创建连接后,如果maxLifetime 大于0 ,则会起一个定时任务,在 maxLifetime(做了点时间随机) 之后会移除这个连接;不管这个连接是否最近还在用, 非常硬气;也就是说
maxLifetime 表示的是连接在创建后最大能存活时间,与最近活跃/空闲与否无关
但是在高并发服务里(ygc 频繁) maxLifetime 可能会导致被驱除的连接每隔7小时由于超龄进入到老年代, 如果连接池设置较大 可能会导致fullgc stw过久 (cms 的 final remak阶段 )
为什么它们默认都是7小时?
时下比较常用的 mysql 数据库默认的配置,如果物理连接空闲超过8小时会自动关闭
所以为了保证 minIdleminimumIdle 这些常驻在连接池的连接的活性,防止它们空闲过久,被数据库那边关了,特别是像晚上低峰期12点到早高峰8点刚好超过8小时后,刚进入业务高峰期拿到的连接都是不可用的, 定时检查,提前重建
检查连接可用性的其他参数
druid 检查连接活性的其他参数还有 testOnBorrow、testOnReturn、testWhileIdle
- testOnBorrow 和 testOnReturn 分别是申请连接和归还连接的时候去 执行下 validationQuery 校验,对性能有影响 一般是关闭的
- testWhileIdle 在申请连接的时候,如果连接空闲超过 timeBetweenEvictionRunsMillis 则 validationQuery 校验;对性能没什么影响
hikariCP 没有暴露类似的参数,但是每次申请到连接的时候 都去检查连接是否超过500ms,如果是则检查连接的可用性
testWhileIdle 这种机制不能取代 maxEvictableIdleTimeMillis 和 maxLifetime ,因为它是在申请连接的时候才做判断,比较被动;
和dba确认,数据库服务配置的连接空闲超时时间