设为首页 收藏本站
查看: 1568|回复: 0

[经验分享] mongo-java-driver连接池

[复制链接]

尚未签到

发表于 2016-12-2 08:53:01 | 显示全部楼层 |阅读模式
MongoDB的连接对象是DBPort,所以可以从DBPortPool对象看起,构造函数如下:
DBPortPool( ServerAddress addr , MongoOptions options ){
super"DBPortPool-" + addr.toString() + ", options = " +  options.toString() ,options.connectionsPerHost );
_options =options;
_addr = addr;
_waitingSem = new Semaphore( _options.connectionsPerHost * _options.threadsAllowedToBlockForConnectionMultiplier );
}
可以看出java-driver会为每个ServerAddress创建一个连接池。也是因为MongoDB是在驱动中设置高可用的,可以配置多个MongoS或MongoD的连接。_waitingSem是个很有意思的信号量,他是由connectionsPerHostthreadsAllowedToBlockForConnectionMultiplier相乘得出的,在后面来分析他的用法。
DBPortPool的父类是SimplePool,再来看从父类的构造函数可以看出:
publicSimplePool(String name, int size){
_name = name;
_size = size;
_sem = new Semaphore(size);
}
其中,size就是connectionsPerHost,SimplePool使用connectionsPerHost创建了一个信号量_sem,可以通过_sem在SimplePool中的使用方式来分析一下连接的创建策略。
SimplePool中,通过下面方法申请获取连接的许可证,
privatebooleanpermitAcquired(finallong waitTime) throws InterruptedException {
if(waitTime > 0) {
return_sem.tryAcquire(waitTime, TimeUnit.MILLISECONDS);
       } elseif (waitTime < 0) {
_sem.acquire();
returntrue;
       } else {
return_sem.tryAcquire();
       }
}
获取这个许可有一个等待时间的策略,如果waitTime为0,那么如果可以获取连接就立即返回true,如果不能获取连接就立即返回false;如果设置了waitTime为正数,会等待waitTime毫秒,如果这段时间仍然没有连接可以使用就返回false;如果waitTime就负数,那么会一直等待直到获得许可为止。
这在被调用方法不能设置超时时间的时候,在调用方法中设置超时时间的方法。
这也是一个平衡线程利用率的策略,在一个有限且使用率高的线程池中,让一个线程等待时间过长无疑是一种浪费,MongoDB使用阻塞信号量配置等待时间的方法,配置线程的释放策略。
这个方法是在获取DBPort对象时被调用的,用来申请获取连接的许可:
public T get(long waitTime) throws InterruptedException {
if(!permitAcquired(waitTime)) {
returnnull;
       }
       //获取连接的方法略……
       // t =createNewAndReleasePermitIfFailure();
}
SimplePool是一个获取池对象的基类方法,createNewAndReleasePermitIfFailure方法会调用子类的createNew方法来创建具体对象。然后再看看这个信号量什么时候被释放:
private TcreateNewAndReleasePermitIfFailure() {
try {
           T newMember = createNew();
if(newMember == null) {
thrownew IllegalStateException("null pool members are not allowed");
           }
returnnewMember;
       } catch(RuntimeException e) {
_sem.release();
throw e;
       } catch (Errore) {
_sem.release();
throw e;
       }
  }
可见,在连接创建失败的时候会释放这个信号量。
publicvoid done( T t ){
synchronizedthis ) {
if (_closed) {
               cleanup(t);
return;
           }
           // 释放连接方法略……
       }
_sem.release();
}
还有就是连接使用完毕,要调用done释放连接,信号量就会被恢复。
从上可知。connectionPerHost是单个Mongo服务连接地址的连接池数量,连接都被占用的获取连接等待时间是可设置的,由MongoClientOptions.maxWaitTime参数决定,默认时间是两分钟,可以通过减少这个值来提升线程利用率。
 
再来看看_waitingSem这个信号量的用法,他只在一个方法中被使用了:
public DBPort get() {
       DBPort port = null;
if ( ! _waitingSem.tryAcquire() )
thrownew SemaphoresOut(_options.connectionsPerHost * _options.threadsAllowedToBlockForConnectionMultiplier);
 
try {
           port = get( _options.maxWaitTime );
       } catch(InterruptedException e) {
thrownew MongoInterruptedException(e);
       } finally {
_waitingSem.release();
       }
if ( port== null )
thrownew ConnectionWaitTimeOut( _options.maxWaitTime );
       port._lastThread =System.identityHashCode(Thread.currentThread());
return port;
}
_waitingSem值的大小是连接池大小乘以一个常数(>=1),这个信号量在获取连接动作之前取得,在获取连接后马上释放,而不用等待连接被放回线程池,说明在线程池为空的情况下,最多可以有(connectionsPerHost* threadsAllowedToBlockForConnectionMultiplier)多个线程被阻塞在
port = get(_options.maxWaitTime)这段代码处。超过这个数就会抛异常,告诉后面的线程不用等了。所以这是一个等待获取连接的队列,队列的长度就是连接池大小乘以一个常数。如果线程池数量有限,而又允许有一定数据损失的场景下,可以将threadsAllowedToBlockForConnectionMultiplier值调小,比如写日志。像MongoDB这种周期性从内存向磁盘写入数据的情况,默认是每60秒写如一次数据,如果内存不够大,可能会在客户端积压很长的等待队列,如果操作比较频繁,而又不想处理因为等待造成的异常,就将这个值调大。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-308469-1-1.html 上篇帖子: mongo添加replicaset的slave或arbiter 下篇帖子: mongo简介——驱动与第三方支持
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表