zoukankan      html  css  js  c++  java
  • 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 单线程池 新建连接

    本文来自博客园,作者:mushishi,转载请注明原文链接:https://www.cnblogs.com/mushishi/p/14665227.html

  • 相关阅读:
    python实现快排算法,传统快排算法,数据结构
    pyaudio音频录制python
    python性能测试,请求QPS测试
    tensorflow如何切换CPU和GPU
    warmup预热学习率
    pytorch两种模型保存方式
    一个简单docker服务镜像的制作,手把手教你制作一个flask的docker容器服务镜像。
    threading的定时器模块,python,每间隔一段时间执行一次任务
    SVM简单分类的使用 sklearn机器学习
    Swoole从入门到入土(18)——WebSocket服务器[心跳ping]
  • 原文地址:https://www.cnblogs.com/mushishi/p/14665227.html
Copyright © 2011-2022 走看看