• 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

  • 相关阅读:
    主机访问虚拟机网络服务失败
    关于接收者为指针的方法
    slice的部分说明
    ES基础知识
    静态语言和动态语言
    数据库设计三大范式
    SparkSQL小例子
    spark小例子
    spark 分析作者发布文章的总阅读量
    spark和hadoop差异
  • 原文地址:https://www.cnblogs.com/mushishi/p/14665233.html
Copyright © 2020-2023  润新知