HikariPool连接池初始化

HikariPool 连接池在初始化的时候主要做了几件事:

  • 初始化底层的连接容器 ConcurrentBag
  • checkFailFast() 尝试创建一个db连接,如果失败则直接抛出初始化异常 中断初始化
  • 初始化各类资源
public HikariPool(final HikariConfig config)
   {
      super(config);
      // 1. 构建自定义的线程池容器 ConcurrentBag
      this.connectionBag = new ConcurrentBag<>(this);
      this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock() : SuspendResumeLock.FAUX_LOCK;

      this.houseKeepingExecutorService = initializeHouseKeepingExecutorService();
		
      // 2. 创建连接,校验有效性 快速失败
      checkFailFast();
      
      // 如果传入opentracing的 metricsTracker就可以上报连接池的一些指标信息
      if (config.getMetricsTrackerFactory() != null) {
         setMetricsTrackerFactory(config.getMetricsTrackerFactory());
      }
      else {
         setMetricRegistry(config.getMetricRegistry());
      }

      setHealthCheckRegistry(config.getHealthCheckRegistry());

      handleMBeans(this, true);

      ThreadFactory threadFactory = config.getThreadFactory();

      final int maxPoolSize = config.getMaximumPoolSize();
			// 3. 连接新增线程池的 blockQueue,上限为 maxPoolSize
      LinkedBlockingQueue<Runnable> addConnectionQueue = new LinkedBlockingQueue<>(maxPoolSize);
      // 4. addConnectionQueueReadOnlyView 用来查看当前有几个db连接任务
      this.addConnectionQueueReadOnlyView = unmodifiableCollection(addConnectionQueue);
      // 5. 构建负责新建db连接的线程池,1个工作线程、队列上限maxPoolSize
      this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue, poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardOldestPolicy());
      // 6. 构建负责关闭db连接的线程池,1个工作线程、队列上限maxPoolSize
      this.closeConnectionExecutor = createThreadPoolExecutor(maxPoolSize, poolName + " connection closer", threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());

			// 7. 连接泄露检测(leakDetectionThreshold默认为0,不开启),db连接从池子中取出后开始计时,如果超过一定的时长还未归还则认为可能发现连接泄露/慢查询了
      this.leakTaskFactory = new ProxyLeakTaskFactory(config.getLeakDetectionThreshold(), houseKeepingExecutorService);
			// 8. houseKeepingExecutor 定时任务,用来维护连接池内 minimumIdle个连接
			// 间隔30ms检查一次连接池,如果不足 minimumIlde则填充,超过minimumIlde~maxPoolSize的那部分连接如果空闲时长 > idleTimeout则关闭掉
      this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(**new HouseKeeper()**, 100L, housekeepingPeriodMs, MILLISECONDS);

			// 如果系统变量设置的阻塞等待 连接池填充完毕,则会等待 houseKeeperTask 把连接池填充完毕 
     if (Boolean.getBoolean("com.zaxxer.hikari.blockUntilFilled") && config.getInitializationFailTimeout() > 1) {
				 // 给负责新建db连接的线程池 加大火力
         addConnectionExecutor.setCorePoolSize(Math.min(16, Runtime.getRuntime().availableProcessors()));
         addConnectionExecutor.setMaximumPoolSize(Math.min(16, Runtime.getRuntime().availableProcessors()));

         final long startTime = currentTime();
         while (elapsedMillis(startTime) < config.getInitializationFailTimeout() && getTotalConnections() < config.getMinimumIdle()) {
            quietlySleep(MILLISECONDS.toMillis(100));
         }
				
         addConnectionExecutor.setCorePoolSize(1);
         addConnectionExecutor.setMaximumPoolSize(1);
      }
   }

几个关键对象:

  • addConnectionExecutor : 负责新建db连接的线程池 1个工作线程、队列上限maxPoolSize
  • addConnectionQueueReadOnlyView : 是 addConnectionExecutor 的阻塞队列视图,用来获取当前有几个db连接等待创建,避免提交过多新建任务导致超过max
  • closeConnectionExecutor: 负责关闭db连接的线程池 1个工作线程、队列上限maxPoolSize
  • leakTaskFactory : db连接泄露任务工厂,在db连接申请成功后创建连接泄露检查任务,如果超过一定时长为归还 则认为连接泄露了(没有close 或者慢查询) 默认 leakDetectionThreshold = 0 不开启
  • houseKeeperTask : ”大管家“定时任务,定时检查连接池内连接数,维持到 minimumIdle 的数量 HouseKeeper

HouseKeeper#run() 为了维持连接池的连接数量稳定在 minimumIdle 个

  1. 池内空闲的连接, 超过 minimumIdle 的那部分,如果空闲超过 idleTimeout 则清除掉
String afterPrefix = "Pool ";
if (idleTimeout > 0L && config.getMinimumIdle() < config.getMaximumPoolSize()) {
   logPoolState("Before cleanup ");
   afterPrefix = "After cleanup  ";

   final List<PoolEntry> notInUse = connectionBag.values(**STATE_NOT_IN_USE**);
   int toRemove = notInUse.size() - config.getMinimumIdle();
   for (PoolEntry entry : notInUse) {
      if (toRemove > 0 && elapsedMillis(entry.lastAccessed, now) > idleTimeout && connectionBag.reserve(entry)) {
         closeConnection(entry, "(connection has passed idleTimeout)");
         toRemove--;
      }
   }
}
  1. 调用 fillPool(); 空闲db连接数补足到 minimumIdle 个
private synchronized void fillPool()
{
   final int connectionsToAdd = Math.min(config.getMaximumPoolSize() - getTotalConnections(), config.getMinimumIdle() - getIdleConnections()) - addConnectionQueueReadOnlyView.size(); //这时候 addConnectionExecutor 的队列视图就有用了
   if (connectionsToAdd <= 0) logger.debug("{} - Fill pool skipped, pool is at sufficient level.", poolName);

   for (int i = 0; i < connectionsToAdd; i++) {
      addConnectionExecutor.submit((i < connectionsToAdd - 1) ? poolEntryCreator : postFillPoolEntryCreator);
   }
}
  • 待填充的db连接个数 = Math.min( 「最大连接数 - 总连接数」, 「最小空闲连接数 - 当前空闲连接数」) - 等待新建db连接的连接数
    这边会扣除正在进行的连接新建任务数 addConnectionQueueReadOnlyView.size() 避免重复新增
  • 提交给 addConnectionExecutor 单线程池 新建连接
posted @ 2021-04-16 00:37  mushishi  阅读(5774)  评论(1编辑  收藏  举报