druid的maxEvictableIdleTimeMillis 和 hikariCP 的 maxLifetime

先看看 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小时会自动关闭

所以为了保证 minIdle\minimumIdle 这些常驻在连接池的连接的活性,防止它们空闲过久,被数据库那边关了,特别是像晚上低峰期12点到早高峰8点刚好超过8小时后,刚进入业务高峰期拿到的连接都是不可用的, 定时检查,提前重建

检查连接可用性的其他参数

druid 检查连接活性的其他参数还有 testOnBorrow、testOnReturn、testWhileIdle

  • testOnBorrow 和 testOnReturn 分别是申请连接和归还连接的时候去 执行下 validationQuery 校验,对性能有影响 一般是关闭的
  • testWhileIdle 在申请连接的时候,如果连接空闲超过 timeBetweenEvictionRunsMillis 则 validationQuery 校验;对性能没什么影响

hikariCP 没有暴露类似的参数,但是每次申请到连接的时候 都去检查连接是否超过500ms,如果是则检查连接的可用性

testWhileIdle 这种机制不能取代 maxEvictableIdleTimeMillis 和 maxLifetime ,因为它是在申请连接的时候才做判断,比较被动;

和dba确认,数据库服务配置的连接空闲超时时间

posted @ 2021-04-16 00:36  mushishi  阅读(1766)  评论(0编辑  收藏  举报