** 转载请注明源链接:http://www.cnblogs.com/wingsless/p/6188659.html

boneCP是一款关注高性能的数据库连接池产品 github主页

不过最近作者好像没有心思更新了,因为他发现了一款更快的连接池产品,但是这不影响我学习它。

连接的生存时间

MySQL有一个重要的参数wait_timeout,用于规定一个connection最大的idle时间,默认是28800秒,即每个connection连续的sleep状态不能超过该值,否则MySQL会自动回收该connection。

连接池的作用是管理连接,任何想要请求数据库连接的行为都和连接池发生交互,从连接池里申请连接,使用完成后将连接交还给连接池。

在一个比较空闲的系统上,连接可能长时间的处于sleep状态,那么一旦达到了MySQL wait_timeout的规定时间,MySQL就要回收连接,这时连接池如果仍然认为该connection可用,待应用向连接池请求时,就会将不存在的connection资源交给应用,这样就会报错。

因此连接池需要一套机制保证每一个connection在连接池生存期内是始终可用的。

我推测应该有两种机制:定期检测和申请时检测。

boneCP采用定期检测机制,即每隔一个时间间隔就会检查其管理的连接处于sleep状态的时间,如果超过了设定的值,则会将此connection重建。

boneCP中有两个很重要的参数:idleConnectionTestPeriodInSeconds和idleMaxAgeInSeconds,分别是连接探测时间阈值和连接最大空闲时间,默认值为4小时和1小时。

boneCP会启动三个线程来进行定期任务:

this.keepAliveScheduler =  Executors.newScheduledThreadPool(this.config.getPartitionCount(), new CustomThreadFactory("BoneCP-keep-alive-scheduler"+suffix, true));
this.maxAliveScheduler = Executors.newScheduledThreadPool(this.config.getPartitionCount(), new CustomThreadFactory("BoneCP-max-alive-scheduler"+suffix, true));
this.connectionsScheduler = Executors.newFixedThreadPool(this.config.getPartitionCount(), new CustomThreadFactory("BoneCP-pool-watch-thread"+suffix, true));

其中keepAliveScheduler用来每隔一段时间检查connection的sleep状态时间是否达到了idleMaxAgeInSeconds或者是否已经失效,如果是,则会将连接kill掉,主要的逻辑见ConnectionTesterThread.java。

需要注意的是,在默认的配置下,该检查的调度是这样定义的:

this.keepAliveScheduler.scheduleAtFixedRate(connectionTester,delayInSeconds, delayInSeconds, TimeUnit.SECONDS);

此时delayInSeconds的值是取idleMaxAgeInSeconds值,即1小时,实际上只要idleMaxAgeInSeconds小于idleConnectionTestPeriodInSeconds,则delayInSeconds一定是idleMaxAgeInSeconds。这样,该线程每1小时就会启动一次,同时要检查时间阈值就会变成1小时。

keepalive线程要执行的命令是这样的:

final Runnable connectionTester = new ConnectionTesterThread(connectionPartition, this, this.config.getIdleMaxAge(TimeUnit.MILLISECONDS), this.config.getIdleConnectionTestPeriod(TimeUnit.MILLISECONDS), queueLIFO);

下面是对ConnectionTesterThread类的解析:

	protected ConnectionTesterThread(ConnectionPartition connectionPartition,
BoneCP pool, long idleMaxAgeInMs, long idleConnectionTestPeriodInMs, boolean lifoMode){
this.partition = connectionPartition;
this.idleMaxAgeInMs = idleMaxAgeInMs; //60 * 60 * 1000
this.idleConnectionTestPeriodInMs = idleConnectionTestPeriodInMs; //240 * 60 * 1000
this.pool = pool;
this.lifoMode = lifoMode;
}

上面代码中,两个主要时间用注释标明。

在该类中最重要的两段代码是用来判断connection的sleep时间是否超标的,只需要对比现在时间和connection最后一次使用时间中间的时间间隔就可以:

// check if connection has been idle for too long (or is marked as broken)
if (connection.isPossiblyBroken() || ((this.idleMaxAgeInMs > 0) && ( System.currentTimeMillis()-connection.getConnectionLastUsedInMs() > this.idleMaxAgeInMs))){
// kill off this connection - it's broken or it has been idle for too long
closeConnection(connection);
continue;
}

上一段代码判断connection是否sleep时间超过了idleMaxAgeInMs的规定(默认3600000ms)。

if (this.idleConnectionTestPeriodInMs > 0 && (currentTimeInMs-connection.getConnectionLastUsedInMs() > this.idleConnectionTestPeriodInMs) &&
(currentTimeInMs-connection.getConnectionLastResetInMs() >= this.idleConnectionTestPeriodInMs)) {
// send a keep-alive, close off connection if we fail.
if (!this.pool.isConnectionHandleAlive(connection)){
closeConnection(connection);
continue;
}
// calculate the next time to wake up
tmp = this.idleConnectionTestPeriodInMs;
if (this.idleMaxAgeInMs > 0){ // wake up earlier for the idleMaxAge test?
tmp = Math.min(tmp, this.idleMaxAgeInMs);
}
}

如果保持默认值,或者设置的值中idleConnectionTestPeriodInMs大于idleMaxAgeInMs的,则这段代码理论上讲不会执行。但是无论如何,这个类都是用来杀死connection的。

接下来继续看BoneCP类,在确定了keepalive调度之后(没有设置maxConnectionAgeInSeconds参数),程序会继续执行到

this.connectionsScheduler.execute(new PoolWatchThread(connectionPartition, this));

这段代码最主要的目的就是新建connection。如果没有设置,则会根据partition最大连接数和已创建连接数进行计算,决定下次新建的连接数。

至于一次新建多少连接,由该类PoolWatchThread.java中的这句决定:

fillConnections(Math.min(maxNewConnections, this.partition.getAcquireIncrement()));

而重要的参数maxNewConnections则是这样计算出来的:

maxNewConnections = this.partition.getMaxConnections()-this.partition.getCreatedConnections();

根据我对代码debug的情况看,连接新建无非分两个情况:keepalive杀死超时连接后和调用getConnection方法后。

让人奇怪的是为什么连接里明明有sleep的连接,却非要新建一个给客户端用?

跟代码发现了这个类:DefaultConnectionStrategy.java

if (!connectionPartition.isUnableToCreateMoreTransactions()){ // unless we can't create any more connections...
this.pool.maybeSignalForMoreConnections(connectionPartition); // see if we need to create more
}

注释中写了,除非是没办法新建连接了(因为到了上限),否则就会新建连接,此时需要了解maybeSignalForMoreConnections这个方法是干什么的?

于是又要回到BoneCP类:

/**
* Tests if this partition has hit a threshold and signal to the pool watch thread to create new connections
* @param connectionPartition to test for.
*/
protected void maybeSignalForMoreConnections(ConnectionPartition connectionPartition) { if (!connectionPartition.isUnableToCreateMoreTransactions()
&& !this.poolShuttingDown &&
connectionPartition.getAvailableConnections()*100/connectionPartition.getMaxConnections() <= this.poolAvailabilityThreshold){
connectionPartition.getPoolWatchThreadSignalQueue().offer(new Object()); // item being pushed is not important.
}
}

好了,发现问题关键了:

connectionPartition.getAvailableConnections()*100/connectionPartition.getMaxConnections() <= this.poolAvailabilityThreshold

这个判断很重要,poolAvailabilityThreshold这个值是0,这是默认值,也没设置过,由此可以推断connectionPartition.getAvailableConnections()一定为0(分母不可能为0,所以分子肯定是0)。

再看看connectionPartition.getAvailableConnections()是干什么的,从名字上看是获得可用连接的,那么明显没有获得可用连接:

protected int getAvailableConnections() {
return this.freeConnections.size();
}

freeConnections是一个Queue,它的size现在来看应该是0,也就是说没有free的connection。

但是明明初始化连接池的时候已经建立了连接的,而且我是调试程序,根本没有可能使用到已经建立的连接,为什么呢?

这个情况只在只建立了一个连接的时候才会出现,这是因为这个类DefaultConnectionStrategy.java的这句:

result = connectionPartition.getFreeConnections().poll();

在这一句执行之前,connectionPartition中的freeConnection属性中是有一个连接的,但是在poll执行之后,该连接被取出,因此freeConnection属性变成了一个空的Queue,size自然就是0了。所以该情况在最开始有一个以上连接的时候就不再存在了。

这也是正常的,因为只有一个connection对于pool来说是不安全的,请求了一个之后新建一个给之后的请求做准备。

*转载请注明源链接:http://www.cnblogs.com/wingsless/p/6188659.html

boneCP原理研究的更多相关文章

  1. AX中四种库存ABC分析法原理研究

    库存ABC分类,简单的说就是抓大放小,是为了让我们抓住重点,用最大精力来管理最重要的物料,而对于不太重要的物料则可以用较少的精力进行管理.它和我们平常说的八二法则有异曲同工之妙. 既然要应用库存ABC ...

  2. SpringMVC关于json、xml自动转换的原理研究[附带源码分析 --转

    SpringMVC关于json.xml自动转换的原理研究[附带源码分析] 原文地址:http://www.cnblogs.com/fangjian0423/p/springMVC-xml-json-c ...

  3. wepy原理研究

    像VUE一样写微信小程序-深入研究wepy框架 https://zhuanlan.zhihu.com/p/28700207 wepy原理研究 虽然wepy提升了小程序开发体验,但毕竟最终要运行在小程序 ...

  4. SpringMVC关于json、xml自动转换的原理研究[附带源码分析]

    目录 前言 现象 源码分析 实例讲解 关于配置 总结 参考资料 前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:http://www.c ...

  5. SpringMVC关于json、xml自动转换的原理研究

    SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:http://www.cnblogs.com/fangjian0423/p/springMVC ...

  6. NNs(Neural Networks,神经网络)和Polynomial Regression(多项式回归)等价性之思考,以及深度模型可解释性原理研究与案例

    1. Main Point 0x1:行文框架 第二章:我们会分别介绍NNs神经网络和PR多项式回归各自的定义和应用场景. 第三章:讨论NNs和PR在数学公式上的等价性,NNs和PR是两个等价的理论方法 ...

  7. [日常] MySQL的哈希索引和原理研究测试

    1.哈希索引 :(hash index)基于哈希表实现,只有精确匹配到索引列的查询,才会起到效果.对于每一行数据,存储引擎都会对所有的索引列计算出一个哈希码(hash code),哈希码是一个较小的整 ...

  8. Java运行原理研究(未完待续)

    java的介绍和定性 java的优缺点分析 jdk的组成结构 jvm的工作原理 java的跨平台原理 java的编译和运行过程

  9. Oracle中读取数据一些原理研究

    文章很多摘录了 http://blog.163.com/liaoxiangui@126/blog/static/7956964020131069843572/ 同时基于这篇文章的基础上,补充一些学习要 ...

随机推荐

  1. CentOS 6.5 搭建 LAMP 环境

    目录 第一步: 安装和配置Apache服务器 第二步: 设置.绑定站点目录文件 第三步: 安装MYSQL数据库 第四步: 安装PHP环境 总结 >>Begin: 第一步: 安装和配置Apa ...

  2. CentOS安装zip unzip命令

    yum install zip unzip

  3. Python读写excel

    #-*- coding:utf-8 -*- #__author__ = 'liu-ke' import xlrd from xlutils.copy import copy mybook = xlrd ...

  4. .Net中的并行编程-5.流水线模型实战

    自己在Excel整理了很多想写的话题,但苦于最近比较忙(其实这是借口).... 上篇文章<.Net中的并行编程-4.实现高性能异步队列>介绍了异步队列的实现,本篇文章介绍我实际工作者遇到了 ...

  5. js 小数[非]四舍五入

    1.四舍五入 (2.678).toFixed(2) // 2.68 2.不需要四舍五入 (parseInt(2.678*100)/100.0).toFixed(2) // 2.67 3.字节单位转换 ...

  6. ZOOM - 简单易用的 jQuery 照片相册插件

    jQuery 最令人印象深刻的应用之一就是对图片的处理,它可以让帮助你在你的项目中加入一些让人惊叹的图片切换效果.ZOOM 是一款全屏效果的 jQuery 图片切换展示插件,支持键盘前后按键切换,支持 ...

  7. React Canvas:高性能渲染 React 组

    React Canvas 提供了使用 Canvas 渲染移动 Web App 界面的能力,替代传统的 DOM 渲染,具有更接近 Native App 的使用体验.React Canvas 提供了一组标 ...

  8. Unicode Character Table – Unicode 字符大全

    Unicode(统一码.万国码.单一码)是一种在计算机上使用的字符编码.它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言.跨平台进行文本转换.处理的要求.Unicode Chara ...

  9. SAP中删除假脱机请求

    好几次公司的SAP都碰到所有的SMARTFORM都打印不了的情况.查了一下原因原来是假脱机请求太多了.清了一下,问题就解决了.    删除假脱机请求的一些方法:    1.避免经常出现此类错误,最好还 ...

  10. 全信号高清DVI编码器|上海视涛科技

    高清DVI编码器(E700)简介 高清DVI编码器是上海视涛科技出品的高性能全信号DVI编码产品.该DVI编码器是上海视涛科技完全自主研发,并适用于DVI信号的编码采集及网络传输的专用硬件设备.可兼容 ...