Ich versuche node.js mit mongodb (2.2.2) zusammen mit dem nativen node.js Laufwerk von 10gen.Was ist der richtige Weg, um mit Mongodb-Verbindungen umzugehen?
Am Anfang lief alles gut. Aber als wir zum Concurrency-Benchmarking-Teil kamen, traten viele Fehler auf. Häufiges connect/Schließen mit 1000 Nebenläufigkeiten verursachen kann mongodb ablehnen weitere Wünsche mit Fehlern wie:
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
Auch wenn viele Kunden Abschaltung ohne explizite schließt, wird es mongodb Minuten, um sie zu erkennen und zu schließen. Das wird auch ähnliche Verbindungsprobleme verursachen. (Mit /var/log/mongodb/mongodb.log, um den Verbindungsstatus zu überprüfen)
Ich habe viel versucht. Laut dem Handbuch, mongodb keine Verbindungsbeschränkung, aber poolSize Option scheint keine Auswirkungen auf mich zu haben.
Da ich nur mit dem node-mongodb-nativen Modul damit gearbeitet habe, bin ich mir nicht sicher, was letztendlich das Problem verursacht hat. Was ist mit der Leistung in anderen Sprachen und Treibern?
PS: Momentan ist die Verwendung eines selbstverwalteten Pools die einzige Lösung, die ich herausgefunden habe, aber die Verwendung kann das Problem mit dem Replikat nicht lösen. Laut meinem Test scheint Replica Set viel weniger Verbindungen als Standalone Mongodb zu nehmen. Aber habe keine Ahnung, warum das passiert.
Concurrency Testcode:
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-Pool-Lösung:
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);
})
}
})
})
Obwohl Node.js einen einzigen Prozess und Ereignismodell verwendet, aber IO Maßnahmen sollten immer async sein. Was meiner Meinung nach nicht die Ursache meiner Probleme sein könnte. Aber ich werde versuchen, wie du zitiert hast, danke. – Jack
Sie vermissen den Punkt, in Ihrem ersten Beispiel; Dieser Code entspricht dem 1000-fachen Starten Ihrer Mongo-App. Sie sollten .connect nur einmal in Ihrer App anrufen. –
Ja, das ist ein Problem, und der Grund ist, dass MongoClient einen Verbindungspool selbst hält, der teurer wird als andere dbs. Aber nicht das Problem mit dem Einzelprozessmodell von node.js. – Jack