Mongo打开了太多连接

时间:2011-10-25 14:39:45

标签: java mongodb connection mongo-java

我试图在Java循环中向MongoDB写入大量数据。我根据打开的连接数得到错误。

我的理论是,由于MongoDB不是事务性的,因此可以同时打开许多连接。然而,Java代码也能够非常快地循环,在一定时间之后,循环迭代的次数开始超过可用连接的数量并且Mongo碰到了墙。

我的代码看起来像这样。我已经看到它建议不要m.close()但是你只是更快地得到错误。

public static void upsert(){
    Mongo m = null;
    DB db = null;

    try {
    m = new Mongo("localhost");
    db = m.getDB("sempedia");    } catch (UnknownHostException e1) { e1.printStackTrace(); } catch (MongoException e1) { e1.printStackTrace(); }

    // create documents
    // I am doing an upsert - hence the doc, doc
    DBCollection triples;
try {
        triples = db.getCollection("triples");
        triples.update(doc,doc,true,false); 
    } catch (MongoException e) { e.printStackTrace(); }

    m.close();
}

在我的java控制台中,我收到此错误:

  

警告:使用0确定maxBSON大小的异常   java.net.SocketException:连接重置

mongodb给出了这个错误:

  

10月25日星期二22:31:39 [initandlisten]连接被拒绝了   许多开放的联系:204 of 204

处理这个问题最优雅的方法是什么?

2 个答案:

答案 0 :(得分:20)

您正在为每个单独的操作创建Mongo类的实例。这不起作用,因为每个实例将创建并保持至少一个连接(但默认情况下为10),并且只有在Java GC清理Mongo实例或调用close()时才会删除这些连接。

问题在于,在这两种情况下,即使使用单个线程,您创建它们的速度也比它们关闭的速度快。这将匆忙耗尽最大量的连接。正确的解决方法是使用单例模式保留一个Mongo实例(Mongo.Holder为此提供了功能,请尝试使用Mongo.Holder.connect(..))。快速“修复”是增加机器上的文件描述符限制,因此最大连接数量要高得多,但显然最终可能会达到相同的限制。您可以使用(在shell中)检查当前最大值:

db.serverStatus().connections

TL; DR:将一个Mongo实例视为一个单例并使它们尽可能长寿,你就是金色的。使用静态方法getInstance()实现一个MongoFactory,它返回一个延迟创建的实例就可以了。祝你好运。

答案 1 :(得分:4)

每次通过您的方法时,您都会制作一个新的MongoClient。

我也有这个问题,但是我解决了它制作checkConnection功能:

private static DBCollection checkConnection(String collection) throws UnknownHostException{
    if(db == null){
        db = (new MongoClient(host, port)).getDB(database);
    }
    return db.getCollection(collection);
}

在您实例化变量的顶部,请执行以下操作:

private static DB db = null;
private static String database = "<Your database>";
private static String host = "localhost"; //<--- usually localhost
private static int port = 27017; //<---- usually 27017, but you can change it.

然后当您制作方法时,请按照以下方式进行操作:

 public <whatever> someFunction() throws UnknownHostException{
    DBCollection dbCollection = checkConnection("triples"); //<--- can be "triples"
                                                    //or whatever collection you want

     <REST OF YOUR FUNCTION HERE USING THE AMAZING COLLECTION
 }

这种方法有一些优势:

- Code reusability, you won't have to write the same thing at every method
- Readability, which programmer doesn't understand this: 
  DBCollection dbCollection = checkConnection("triples");  
- ONLY ONE CONNECTION WHICH YOU RE-USE (this doesn't affect data not being synced)

希望我帮助