• Hikari连接的创建过程


    HouseKeeper 和 HikariPool#addBagItem 在需要新增db连接的时候,都是往负责连接创建的线程池 addConnectionExecutorPoolEntryCreator implements Callable<Boolean> 任务

    PoolEntryCreator#call()

    public Boolean call(){
        long sleepBackoff = 250L;
    		**// 1.** 判断是否需要创建
        while (poolState == POOL_NORMAL && **shouldCreateAnotherConnection()**) {
          **// 2.** 创建db连接条目
          final PoolEntry poolEntry = createPoolEntry();
          if (poolEntry != null) {
             connectionBag.add(poolEntry);
             logger.debug("{} - Added connection {}", poolName, poolEntry.connection);
             if (loggingPrefix != null) {
                logPoolState(loggingPrefix);
             }
             return Boolean.TRUE;
          }
    			
    			**// 3.** 休眠后重试
          // failed to get connection from db, sleep and retry
          if (loggingPrefix != null) logger.debug("{} - Connection add failed, sleeping with backoff: {}ms", poolName, sleepBackoff);
          quietlySleep(sleepBackoff);
          sleepBackoff = Math.min(SECONDS.toMillis(10), Math.min(connectionTimeout, (long) (sleepBackoff * 1.5)));
       }
    
       // Pool is suspended or shutdown or at max size
    	return Boolean.FALSE;
    }
    

    1. while (poolState == POOL_NORMAL && shouldCreateAnotherConnection()) { .. } 判断是否需要创建

    private synchronized boolean shouldCreateAnotherConnection() {
             return getTotalConnections() < config.getMaximumPoolSize() &&
                (connectionBag.getWaitingThreadCount() > 0 || getIdleConnections() < config.getMinimumIdle());
    }
    

    当前总的连接数小于 maximumPoolSize 最大连接数的前提下,如果有线程等待 db连接 或 池内空闲线程数小于最小空闲线程数 才会去创建新db连接

    2. final PoolEntry poolEntry = createPoolEntry(); 创建db连接条目,成功的话添加到池子 connectionBag 里

    private PoolEntry createPoolEntry()
       {
          try {
             final PoolEntry poolEntry = newPoolEntry();
    
             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(new MaxLifetimeTask(poolEntry), lifetime, MILLISECONDS));
             }
    
             final long keepaliveTime = config.getKeepaliveTime();
             if (keepaliveTime > 0) {
                // variance up to 10% of the heartbeat time
                final long variance = ThreadLocalRandom.current().nextLong(keepaliveTime / 10);
                final long heartbeatTime = keepaliveTime - variance;
                poolEntry.setKeepalive(houseKeepingExecutorService.scheduleWithFixedDelay(new KeepaliveTask(poolEntry), heartbeatTime, heartbeatTime, MILLISECONDS));
             }
    
             return poolEntry;
          }
        //...
        return null;
    }
    
    • newPoolEntry() 创建连接对象,它内部会创建db物理连接并且执行一下 connectionInitSql 语句
    • 如果设置了 maxLifetime(默认7小时) ,先随机减去 2.5% maxLifetime的时间,避免多个连接在同一个时间被清除掉,对db造成瞬时连接压力
      则会起一个任务 MaxLifeTimeTask 在这个连接创建后 maxLifetime 的时候将其清除(标记为 evict,如果此时连接空闲则直接关闭物理连接,不然要等到下次被取出时再关闭 HikariPool#geConnection 内逻辑)
    • 如果设置了 keepaliveTime (默认是0), 则开启定时任务,每隔 keepaliveTime(加了随机值) 检查db物理连接的可用性 jdbc4.isValid 或者执行下 connectionTestQuery 语句

    maxLifetime 连接创建后的最大存活时间,超过后就会被清除
    keepaliveTime 则是多久检查一次连接的活性,必须比 maxLifetime小 , 在申请到的连接空闲超过一定时间的话,在使用前也会记性 alive 活性判断,一般keepaliveTime 也没大必要

    • 创建成功的话,就退出循环了

    3. 如果db连接创建失败,则休眠 250ms 后,再进入while逻辑,重新尝试

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

  • 相关阅读:
    背水一战 Windows 10 (61)
    背水一战 Windows 10 (60)
    背水一战 Windows 10 (59)
    背水一战 Windows 10 (58)
    背水一战 Windows 10 (57)
    背水一战 Windows 10 (56)
    背水一战 Windows 10 (55)
    背水一战 Windows 10 (54)
    背水一战 Windows 10 (53)
    背水一战 Windows 10 (52)
  • 原文地址:https://www.cnblogs.com/mushishi/p/14665233.html
Copyright © 2020-2023  润新知