写点什么

druid 源码阅读 7——keepAlive 实现方式

作者:张大彪
  • 2022 年 5 月 17 日
  • 本文字数:1765 字

    阅读完需:约 6 分钟

这篇文章尝试回答一下秦老师提出的问题,druid keepAlive 实现方式?

查找思路:

总共有两个相关参数:

dataSource.setKeepAlive(true);dataSource.setKeepAliveBetweenTimeMillis(100000);
复制代码


keepAlive(默认关闭)功能:

一、初始化连接池时会填充到 minIdle 数量

if (keepAlive) {  // async fill to minIdle  if (createScheduler != null) {    for (int i = 0; i < minIdle; ++i) {      submitCreateTask(true);    }  } else {    this.emptySignal();  }}
复制代码

追到这个地方:com.alibaba.druid.pool.DruidDataSource.CreateConnectionTask#runInternal

// 必须存在线程等待,才创建连接if (poolingCount >= notEmptyWaitThreadCount //    && (!(keepAlive && activeCount + poolingCount < minIdle)) // 在keepAlive场景不能放弃创建    && (!initTask) // 线程池初始化时的任务不能放弃创建    && !isFailContinuous() // failContinuous时不能放弃创建,否则会无法创建线程    && !isOnFatalError() // onFatalError时不能放弃创建,否则会无法创建线程   ) {  clearCreateTask(taskId);  return;}
复制代码

和这个地方:com.alibaba.druid.pool.DruidDataSource.CreateConnectionThread#run

if (emptyWait) {  // 必须存在线程等待,才创建连接  if (poolingCount >= notEmptyWaitThreadCount //      && (!(keepAlive && activeCount + poolingCount < minIdle))      && !isFailContinuous()     ) {    empty.await();  }
// 防止创建超过maxActive数量的连接 if (activeCount + poolingCount >= maxActive) { empty.await(); continue; }}
复制代码

这几个地方代表一个意思:初始化连接池和新建连接的逻辑中,会把连接数填充到 minIdle 数量。


二、连接池中的 minIdle 数量以内的连接,空闲时间超过 minEvictableIdleTimeMillis,则会执行 keepAlive 操作,打开会一直保持 minIdle 的数量值;

com.alibaba.druid.pool.DruidDataSource.DestroyTask#run

public void run() {  shrink(true, keepAlive);
if (isRemoveAbandoned()) { removeAbandoned(); }}
复制代码

对应到这里:com.alibaba.druid.pool.DruidDataSource#shrink(boolean, boolean)

有两个地方用 keepalive 判断。

1、如果 idle 时间大于探活时间,

if (keepAlive && idleMillis >= keepAliveBetweenTimeMillis) {    keepAliveConnections[keepAliveCount++] = connection;}
复制代码


2、如果当前连接数小于 minIdle,进行连接数的补充。

if (keepAlive && poolingCount + activeCount < minIdle) {    needFill = true;}
复制代码


最终遍历并探活 keepAliveConnections 的代码在这里:

if (keepAliveCount > 0) {    // keep order    for (int i = keepAliveCount - 1; i >= 0; --i) {        DruidConnectionHolder holer = keepAliveConnections[i];        Connection connection = holer.getConnection();        holer.incrementKeepAliveCheckCount();
boolean validate = false; try { this.validateConnection(connection); validate = true; } catch (Throwable error) { if (LOG.isDebugEnabled()) { LOG.debug("keepAliveErr", error); } // skip }
boolean discard = !validate; if (validate) { holer.lastKeepTimeMillis = System.currentTimeMillis(); boolean putOk = put(holer, 0L, true); if (!putOk) { discard = true; } }
if (discard) { try { connection.close(); } catch (Exception e) { // skip }
lock.lock(); try { discardCount++;
if (activeCount + poolingCount <= minIdle) { emptySignal(); } } finally { lock.unlock(); } } } this.getDataSourceStat().addKeepAliveCheckCount(keepAliveCount); Arrays.fill(keepAliveConnections, null);}
复制代码


用户头像

张大彪

关注

还未添加个人签名 2018.04.25 加入

还未添加个人简介

评论

发布
暂无评论
druid 源码阅读 7——keepAlive实现方式_张大彪_InfoQ写作社区