想知道小蜜蜂链接池性能为啥这么高吗?

相信不少看太小蜜蜂(BeeCP)链接池的性能对比图的网友都会以为惊讶不已,这比被号称史上最快的光链接池还快啊,简直难以想象!想知道它性能强悍的缘由吗?今天就为你们解开这个谜团。git

链接借用

故事仍是要从链接池自己提及,链接池技术是一门古老的IT技术,其本质并不复杂,其工做原理相似图书馆,只不过它借出/回收的是链接对象,在链接池类内部通常至少有两条列表,第一条存放链接对象(相似书架),第二条存放等待者线程(或隐式), 若是链接都被借光了,借用者只能排队等待其余借用者归还,等待过程当中,某些等待者可能会由于时间达到最大容许时刻点,则会退出等待,这种离开现象叫等待超时。github

传递与队列

借用在使用完毕后将被关闭(实际关闭只是代理对象而已),背后自动触发链接池对链接的回收,若是在池中存在等待者,那么链接池将回收过来的链接传递给等待者,这是一件颇有意思的事情,各链接池的性能的差别,很大一部分是由传递的速度致使的(谁的传递效率高,谁的性能更强),传递的方式一般是借助于同步队列的管道推拉方式完成的,好比Tomcat-JDBC使用的是闲/忙两条队列,光链接池采用的是同步队列(SynchronousQueue)代码相似:数组

归还线程A:queue.offer(object);

等待线程B:queue.poll(time);

对于线程 B在有效时间范围内进行等待,不管采用LinkedBlockingQueue仍是采SynchronousQueue,背后直接或间接使用了等待链技术,好比SynchronousQueue就比较直白式,自定义了节点链,好比LinkedBlockingQueue则是经过Lock对象来完成的,其实Lock对象的本质就是等待链,有兴趣的同窗能够翻看一下源码,AbstractQueuedSynchronizer对象是Lock的源头,它内部就包含一条CAS节点链,看类上的介绍就清楚了,不用细看代码,通常同窗只是使用而已,又不搞JDK代码开发, 没有必要研究太深。缓存

传递效率分析

对链接池而言,传递的效率直接决定其性能的高低,若是存在大量的并发的时候,其实使用Offer/Poll的方式,性能并不会很理想,以SynchronousQueue为例说明:A为归还线程,B为等待者线程,C为刚进入的借用者线程,A在归还的时候,首先将链接设置为闲置状态,并经过队列传递给B, 此时C从链接数组中( 或CopyOnWriteArrayList)搜索的时也发现这个刚释放的链接,所以B与C同时经过才CAS的方式抢占这个链接,假如B抢占失败,又未超时,怎么办呢?继续Poll(本质上是再次加入等待链)有可能存在反复出入等待链的状况,你们能够想一想,假如很多线程发生这种状况,那么势必形成性能损耗,甚至出现早加入等待者比后来加入的等待者须要更多时间才得到链接,为啥呢?每次失败后,都是从新加入等待链的末端,从而违背了FIFO原则,理想方式是:我先加入等待,那么我应该比后等待者先得到对象。 (这就是某池在并发比较多的状况,部分请求出现时间夸特别度大的根本缘由)安全

小蜜蜂池如何传递

小蜜蜂链接池采用并发队(ConcurrentLinkedQueue)队列完成等待/传递动做,队列中的等待者在未得到有效的链接前,是不会离开队列的;回收后的链接老是从队列首位置进行传递,所以保正FIFO公平性原则( 按队列排队次序得到传递的机会 ),这个处理方式大大减小不要的队列中移动,从而大大提高传递(Transfer)的效率,这个方式是链接池领域中一次技术创新,是小蜜蜂链接池与其余链接池区分开来的重要标志,我将它称之为小蜜蜂队列技术并发

小蜜蜂链接池在处理Transfer的方式,采用两种业务模式:公平与竞争; 在公平模式下,释放的链接在不改变状态的前提下(状态为使用 中:USING)进行传递,在这个模式下,上述的C线程经过cas的方式是没法持有的,从而保证B能顺利得到此链接;在竞争模式下,B与C抢占这个链接,若是B成功取得后,再检测是有一个有效的链接后,才会离开等待队列;若是B抢占失败后,在未超时间的状况下,那么B是不会离开队列,排列B的后面有B2,B3.....性能

除了拥有这个创新式技术,小蜜蜂链接池还有其余一些亮点,下面一一罗列。优化

1:合理的线程控制url

学过计算机的同窗都知道,CPU是采用分时执行运行时线程的,能够想象一下若是有大量并发的线程同时运行,那么CPU须要再这些线程之间切换运行,势必会形成较大的损耗,小蜜蜂链接池使用信号量(Semaphore:可形象化比喻为一个具备多通道的门)的方式控制并发借用线程数,从而减小CPU一些没必要要的切换。.net

以4核CPU为例,链接的最大个数为8个,将并发控制为4,保证同一时刻4个线程能够进入getConnection方法的信号量内部,指望的理想状态是:4个链接处于待借,4个链接处于使用中,使每一个核覆盖2个线程,这样既不给CPU形成很大压力,又能充分利用CPU

2:合理利用队列与缓存

A: 小蜜蜂链接池中,在两处可能发生等待现象:第一处是等待信号量的许可(信号量背后就是等待链),第二处等待是等待传递(Transfer),处理的方式是:大队列等待,小队列交换,意思是说:在大量并发的状况,信号量的等待链中持有更多的更多等待线程,让小规模的并发队列来完成第二处等待和传递。

B: 小蜜蜂链接池中采用单链接缓存,并在到达信号量位置以前,自行经过CAS的方式尝试抢占曾经使用过的链接(若是多缓存,还不如直接从列表获取呢)

3: 精准控制超时

借用线程进入借用方法(getConnection)后,预先计算超时时刻点(既借用者线程在迟内活动的时刻点不能超过该点),超时时间默认是8秒,意为:8秒之内未取得链接,借用者线程自动离开池方法,这个时间是覆盖池内的两处可能出现等待的时间之和。

4:链接的安全保证

A: JDBC物理队对象经过代理分装,不容许调用者直接获取

B: 链接在使用完毕后,重置处理,避免脏链接归还到池中(若是出现,关闭老的,则补充一个新)

C: 链接有效性判断检查(存活性,闲置超时,持有不用超时)

D: 安全性关闭(若是Close方法被多个并发线程关闭,只能有一个关闭成功)

E: 三连级检查(Result检查本身的close,还要检查Statement是否关闭,再上一级Connection是否关闭)确保对象的安全性

5:代码极致优化

A: PSCache缓存优化(包括hashKey的计算)

B: 去掉一些get/set方法,直接使用对象的属性值

C: 一些CasUpdator不是放对象内部,减小方法调用次数

总之来讲,小蜜蜂链接池是一款优秀的开元做品,但愿推荐给更多公司和我的使用,同时欢迎各位网友提问,或建议,或质疑. 项目工程请访问: [https://github.com/Chris2018998/BeeCP]

相关文章
相关标签/搜索