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 單線程池 新建連接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM