mongodb线程池解析和查询优化
cookqq ›博客列表 ›MongoDB

mongodb线程池解析和查询优化

2015-11-08 20:58:51.0|分类: MongoDB|浏览量: 6745

摘要: mongodb查询query方法要慎用。如果想要查询一个表的所有数据请用cur.iterator()方法。慎用cur.toArray(),这个方法把所有的数据都放到内存中,如果数据量很大,你想想会出现什么情况。 cur.length()同样慎用,这个原因和cur.toArray()一样,也会把所有数据读到内存中,然后得到list大小。 cur.size()同样是获取cur这个游标大小,但是他的原理是再次执行一次查询数据库得到大小


1、mongo查询优化

DBCursor cur = collection.find();
MongoCursor<Document> cursor = cur.iterator();
try {    
   while (cursor.hasNext()) {         
   System.out.println(cursor.next().toJson());   
  } 
} finally {     cursor.close(); }

mongodb查询query方法要慎用。如果想要查询一个表的所有数据请用cur.iterator()方法。慎用cur.toArray(),这个方法把所有的数据都放到内存中,如果数据量很大,你想想会出现什么情况。

cur.length()同样慎用,这个原因和cur.toArray()一样,也会把所有数据读到内存中,然后得到list大小。

cur.size()同样是获取cur这个游标大小,但是他的原理是再次执行一次查询数据库得到大小,源码如下:

  public int size() {
        return (int)_collection.getCount(this._query, this._keysWanted, this._limit, this._skip, getReadPreference(), _maxTimeMS,
                                         MILLISECONDS);
    }






2、mongo连接池分析

今天发现网站运行特别慢,pc浏览器和手机接口传输数据都很慢。最近网站都没有更新,运行了一段时间发现自动慢下来了。mongo连接池如下:

 mongo = new MongoClient(ip, port);
	            // 设置链接参数
	            mongo.getMongoClientOptions().builder()
	            .connectionsPerHost(SystemProperties.getMongoPoolSize())
	            .socketTimeout(SystemProperties.getMongoSocketTimeout())
	            .socketKeepAlive(SystemProperties.getMongoSocketKeepAlive())
	            .threadsAllowedToBlockForConnectionMultiplier(SystemProperties.getMongoThreads())
	            .build();
	            // 完成参数设置


mongno默认的配置信息

参数默认属性解释
connectionsPerHost100(以前默认是10)每个主机的连接数
threadsAllowedToBlockForConnectionMultiplier5(这个数不易设置过大100就可以了)

Sets the multiplier for number of threads allowed to block waiting for a connection this multiplier, multiplied with the connectionsPerHost setting, gives the maximum number of threads that may be waiting for a connection to become available from the pool. All further threads will get an exception right away. For example if connectionsPerHost is 10 and threadsAllowedToBlockForConnectionMultiplier is 5, then up to 50 threads can wait for a connection.线程队列数,它以上面connectionsPerHost值相乘的结果就是线程队列最大值。如果连接线程排满了队列就会抛出“Out of semaphores to get db”错误。

maxWaitTime1000 * 60 * 2最大等待连接的线程阻塞时间
connectTimeout1000 * 10连接超时的毫秒
socketTimeout0socket超时。0是默认和无限
socketKeepAlivefalse
autoConnectRetryfalseSets whether auto connect retry is enabled


关系型数据库中,我们做连接池无非就是事先建立好N个连接(connection),并构建成一个连接池(connection pool),获取连接和释放链接的操作

Mongo m = new Mongo( "localhost" , 27017 );
DB db = m.getDB( "mydb" );
//get collection
DBCollection coll = db.getCollection("testCollection")
//insert
BasicDBObject doc = new BasicDBObject();
...
coll.insert(doc);

官方解释:

Note: The Mongo object instance actually represents a pool of connections to the database; you will only need one object of class Mongo even with multiple threads.  See the concurrency doc page for more information.

The Mongo class is designed to be thread safe and shared among threads. Typically you create only 1 instance for a given DB cluster and use it across your app. If for some reason you decide to create many mongo intances, note that:all resource usage limits (max connections, etc) apply per mongo instance to dispose of an instance, make sure you call mongo.close() to clean up resources。

mongo实例其实已经是一个现成的连接池了,而且线程安全。这个内置的连接池默认初始了10个连接,每一个操作(增删改查等)都会获取一个连接,执行操作后释放连接。

分析插入源代码:

DBCollectionImpl extends DBCollection 类中

 public WriteResult insert(List<DBObject> list, WriteConcern concern, DBEncoder encoder ){
        return insert(list, true, concern, encoder);
    }

    protected WriteResult insert(List<DBObject> list, boolean shouldApply , WriteConcern concern, DBEncoder encoder ){
        if (concern == null) {
            throw new IllegalArgumentException("Write concern can not be null");
        }

        if (encoder == null)
            encoder = DefaultDBEncoder.FACTORY.create();

        if ( willTrace() ) {
            for (DBObject o : list) {
                trace("save:  " + namespace + " " + JSON.serialize(o));
            }
        }

        DBPort port = db.getConnector().getPrimaryPort();
        try {
            if (useWriteCommands(concern, port)) {
                try {
                    return translateBulkWriteResult(insertWithCommandProtocol(list, concern, encoder, port, shouldApply), INSERT, concern,
                                                    port.getAddress());
                } catch (BulkWriteException e) {
                    throw translateBulkWriteException(e, INSERT);
                }
            }
            else {
                return insertWithWriteProtocol(list, concern, encoder, port, shouldApply);
            }
        } finally {
            db.getConnector().releasePort(port);
        }
    }

上面代码插入完成之后都会执行finally代码: db.getConnector().releasePort(port);释放资源。








一键分享文章

分类列表

  • • struts源码分析
  • • flink
  • • struts
  • • redis
  • • kafka
  • • ubuntu
  • • zookeeper
  • • hadoop
  • • activiti
  • • linux
  • • 成长
  • • NIO
  • • 关键词提取
  • • mysql
  • • android studio
  • • zabbix
  • • 云计算
  • • mahout
  • • jmeter
  • • hive
  • • ActiveMQ
  • • lucene
  • • MongoDB
  • • netty
  • • flume
  • • 我遇到的问题
  • • GRUB
  • • nginx
  • • 大家好的文章
  • • android
  • • tomcat
  • • Python
  • • luke
  • • android源码编译
  • • 安全
  • • MPAndroidChart
  • • swing
  • • POI
  • • powerdesigner
  • • jquery
  • • html
  • • java
  • • eclipse
  • • shell
  • • jvm
  • • highcharts
  • • 设计模式
  • • 列式数据库
  • • spring cloud
  • • docker+node.js+zookeeper构建微服务
版权所有 cookqq 感谢访问 支持开源 京ICP备15030920号
CopyRight 2015-2018 cookqq.com All Right Reserved.