Подтвердить что ты не робот

Mongo открывает слишком много соединений

Я пытаюсь написать много данных в MongoDB в цикле Java. Я получаю ошибки, основанные на количестве открытых подключений.

Моя теория заключается в том, что поскольку 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 я получаю эту ошибку:

ПРЕДУПРЕЖДЕНИЕ: Исключение, определяющее размер maxBSON с использованием 0 java.net.SocketException: Соединение reset

И mongodb дает эту ошибку:

Вт Окт 25 22:31:39 [initandlisten] connection отказано, потому что слишком много открытых соединений: 204 из 204

Каким будет самый элегантный способ справиться с этой проблемой?

4b9b3361

Ответ 1

Вы создаете экземпляр класса Mongo для каждой отдельной операции. Это не сработает, поскольку каждый экземпляр создаст и удерживает хотя бы одно соединение (но по умолчанию 10), и эти соединения будут удалены только в том случае, если Java GC очистит ваш экземпляр Mongo или когда вы вызываете close().

Проблема заключается в том, что в обоих случаях вы создаете их быстрее, чем они закрываются даже при использовании одного потока. Это приведет к потоку максимального количества соединений. Правильное исправление заключается в том, чтобы один экземпляр Mongo использовался с использованием шаблона singleton (Mongo.Holder предоставляет для этого функции, попробуйте Mongo.Holder.connect(..)). Быстрое "исправление" заключается в увеличении лимита дескриптора файла на вашем компьютере, поэтому максимальное количество соединений значительно выше, но, очевидно, вы в конечном итоге можете достичь того же предела. Вы можете проверить свой текущий максимум используя (в оболочке):

db.serverStatus().connections

TL; DR: Относитесь к монгольскому экземпляру как к синглоту и делайте его как можно более долговечным, а вы - золотым. Реализация MongoFactory со статическим методом getInstance(), который возвращает лениво созданный экземпляр, отлично справится с этим. Удачи.

Ответ 2

Вы создаете новый 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)

Надеюсь, я помог