2013-03-28 3 views
21

Я пробую node.js с mongodb (2.2.2) вместе, используя родной node.js диск на 10gen.Каков правильный способ работы с соединениями Mongodb?

Сначала все шло хорошо. Но, когда мы приходили к параллельной сравнительной части, происходило много ошибок. Частый Соединить/близко с 1000 параллельно работающим может вызвать MongoDB отклонить любые дальнейшие запросы с ошибкой, как:

Error: failed to connect to [localhost:27017] 

Error: Could not locate any valid servers in initial seed list 

Error: no primary server found in set 

Кроме того, если много отключения клиентов без явного закрытия, это займет MongoDB минут, чтобы обнаружить и закрыть их. Это также вызовет аналогичные проблемы с подключением. (Использование /var/log/mongodb/mongodb.log для проверки состояния соединения)

Я пробовал много. Согласно руководству, mongodb не имеет ограничений на соединение, но poolSize вариант, похоже, не имеет для меня последствий.

Поскольку я работал с ним только в модуле node-mongodb-native, я не очень уверен, что в конечном итоге вызвало проблему. Как насчет производительности на других других языках и драйверах?

PS: В настоящее время использование автономного пула - единственное решение, которое я выяснил, но его использование не может решить проблему с набором реплик. Согласно моему тесту, набор реплик кажется гораздо менее подключенным, чем автономный mongodb. Но понятия не имею, почему это происходит.

Параллелизм код теста:

var MongoClient = require('mongodb').MongoClient; 

var uri = "mongodb://192.168.0.123:27017,192.168.0.124:27017/test"; 

for (var i = 0; i < 1000; i++) { 
    MongoClient.connect(uri, { 
     server: { 
      socketOptions: { 
       connectTimeoutMS: 3000 
      } 
     }, 
    }, function (err, db) { 
     if (err) { 
      console.log('error: ', err); 
     } else { 
      var col = db.collection('test'); 
      col.insert({abc:1}, function (err, result) { 
       if (err) { 
        console.log('insert error: ', err); 
       } else { 
        console.log('success: ', result); 
       } 
       db.close() 
      }) 
     } 
    }) 
} 

решение Generic бассейн:

var MongoClient = require('mongodb').MongoClient; 
var poolModule = require('generic-pool'); 

var uri = "mongodb://localhost/test"; 

var read_pool = poolModule.Pool({ 
    name  : 'redis_offer_payment_reader', 
    create : function(callback) { 
     MongoClient.connect(uri, {}, function (err, db) { 
      if (err) { 
       callback(err); 
      } else { 
       callback(null, db); 
      } 
     }); 
    }, 
    destroy : function(client) { client.close(); }, 
    max  : 400, 
    // optional. if you set this, make sure to drain() (see step 3) 
    min  : 200, 
    // specifies how long a resource can stay idle in pool before being removed 
    idleTimeoutMillis : 30000, 
    // if true, logs via console.log - can also be a function 
    log : false 
}); 


var size = []; 
for (var i = 0; i < 100000; i++) { 
    size.push(i); 
} 

size.forEach(function() { 
    read_pool.acquire(function (err, db) { 
     if (err) { 
      console.log('error: ', err); 
     } else { 
      var col = db.collection('test'); 
      col.insert({abc:1}, function (err, result) { 
       if (err) { 
        console.log('insert error: ', err); 
       } else { 
        //console.log('success: ', result); 
       } 
       read_pool.release(db); 
      }) 
     } 
    }) 
}) 

ответ

22

С Node.js однопоточен вы не должны открывать и закрывать соединение на каждом запросе (как вы будет работать в других многопоточных средах.)

Это цитата с человека, который написал клиентский модуль node.js MongoDB:

«Вы открываете приложение MongoClient.connect один раз, когда ваше приложение загружается и повторно использует объект db. Это не единичный пул соединений каждый .connect создает новый пул соединений. Так откройте его когда-то [d] повторно использовать во всех запросов «. - christkv https://groups.google.com/forum/#!msg/node-mongodb-native/mSGnnuG8C1o/Hiaqvdu1bWoJ

+0

Хотя Node.js использует единый процесс и модель событий, но IO действия всегда должны быть асинхронными. Я думаю, это не может быть причиной моих проблем. Но, я попробую, как вы цитировали, спасибо. – Jack

+2

Вам не хватает точки в первом примере; Этот код эквивалентен началу вашего приложения Mongo 1000 раз. Вы должны только позвонить .connect один раз в своем приложении. –

+0

Да, это проблема, и причина в том, что MongoClient имеет пул соединений, который становится дороже других dbs. Но не проблема с единственной технологической моделью node.js. – Jack

3

Посмотрев в посоветуйте Гектора. Я считаю, что связь Mongodb сильно отличается от некоторых других баз данных, которые я когда-либо использовал. Основное отличие заключается в родной диск в nodejs: MongoClient имеет собственный пул соединений для каждого MongoClient открыт, что размер пула определяется по

server:{poolSize: n} 

Таким образом, открытое соединение 5 MongoClient с PoolSize: 100, означает общий 5 * 100 = 500 соединений с целью Монгодб Ури. В этом случае частые открытые & близкие соединения MongoClient определенно станут огромной нагрузкой для хоста и, наконец, вызовут проблемы с подключением. Вот почему у меня так много проблем.

Но поскольку мой код был написан таким образом, поэтому я использую пул соединений для хранения единственного соединения с каждым отдельным URI и использую простой параллельный ограничитель того же размера, что и poolSize, чтобы избежать ошибок загрузки. ,

Вот мой код:

/*npm modules start*/ 
var MongoClient = require('mongodb').MongoClient; 
/*npm modules end*/ 

// simple resouce limitation module, control parallel size 
var simple_limit = require('simple_limit').simple_limit; 

// one uri, one connection 
var client_pool = {}; 

var default_options = { 
    server: { 
     auto_reconnect:true, poolSize: 200, 
     socketOptions: { 
      connectTimeoutMS: 1000 
     } 
    } 
} 

var mongodb_pool = function (uri, options) { 
    this.uri = uri; 
    options = options || default_options; 
    this.options = options; 
    this.poolSize = 10; // default poolSize 10, this will be used in generic pool as max 

    if (undefined !== options.server && undefined !== options.server.poolSize) { 
     this.poolSize = options.server.poolSize;// if (in)options defined poolSize, use it 
    } 
} 

// cb(err, db) 
mongodb_pool.prototype.open = function (cb) { 
    var self = this; 
    if (undefined === client_pool[this.uri]) { 
     console.log('new'); 

     // init pool node with lock and wait list with current callback 
     client_pool[this.uri] = { 
      lock: true, 
      wait: [cb] 
     } 

     // open mongodb first 
     MongoClient.connect(this.uri, this.options, function (err, db) { 
      if (err) { 
       cb(err); 
      } else { 
       client_pool[self.uri].limiter = new simple_limit(self.poolSize); 
       client_pool[self.uri].db = db; 

       client_pool[self.uri].wait.forEach(function (callback) { 
        client_pool[self.uri].limiter.acquire(function() { 
         callback(null, client_pool[self.uri].db) 
        }); 
       }) 

       client_pool[self.uri].lock = false; 
      } 
     }) 
    } else if (true === client_pool[this.uri].lock) { 
     // while one is connecting to the target uri, just wait 
     client_pool[this.uri].wait.push(cb); 
    } else { 
     client_pool[this.uri].limiter.acquire(function() { 
      cb(null, client_pool[self.uri].db) 
     }); 
    } 
} 

// use close to release one connection 
mongodb_pool.prototype.close = function() { 
    client_pool[this.uri].limiter.release(); 
} 

exports.mongodb_pool = mongodb_pool; 
+0

Здравствуйте, я столкнулся с этой проблемой. и вы могли бы пройти мимо 'var simple_limit = require ('simple_limit'). simple_limit; 'simple_limit.js код? и как использовать 'mongodb_pool'? Благодаря ~ – Eddy

Смежные вопросы