14

我正在尝试在 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 java.net.SocketException 确定 maxBSON 大小的异常:连接重置

mongodb 给出了这个错误:

10 月 25 日星期二 22:31:39 [initandlisten] 连接被拒绝,因为打开的连接太多:204 个,共 204 个

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

4

2 回答 2

22

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

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

db.serverStatus().connections

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

于 2011-10-25T15:40:52.020 回答
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)

希望我有所帮助

于 2014-11-21T10:12:55.973 回答