Cálculo de la memoria necesaria para n grupos de conexiones para mongodb que se ejecutan en la aplicación node.js
performance amazon-ec2 (2)
Estoy tratando de perfilar el rendimiento de mi aplicación node.js ejecutando mongodb actualmente configurado para usar 50 grupos de conexiones. Usando Blazemeter, he estado tratando de hacer una prueba que envía 1000 usuarios simulados a mi punto final. Al ejecutarse en una instancia más pequeña de Amazon EC2 (4 CPU y 7,5 GB de memoria, el rendimiento parecía estar vinculado a la CPU). Cuando comencé a moverme a una máquina más grande con al menos 8 CPU ejecutándose en el modo de clúster pm2, parece que mongodb se está quedando sin memoria. Cuando la prueba llegue a aproximadamente 300-500 usuarios simulados, el proceso de Mongo fallará:
IE recibo un error de todas las consultas de db y vi el siguiente mensaje cuando intento iniciar el shell mongo:
2015-10-26T23:34:56.657+0000 warning: Failed to connect to 127.0.0.1:27017, reason: errno:111 Connection refused
2015-10-26T23:34:56.658+0000 Error: couldn''t connect to server 127.0.0.1:27017 (127.0.0.1), connection attempt failed at src/mongo/shell/mongo.js:146
exception: connect failed
La primera vez que sucedió esto, también encontré el siguiente error en el registro de mongo:
exception in initAndListen: 10309 Unable to create/open lock file: /var/lib/mongodb/mongod.lock errno:13 Permission denied Is a mongod instance already running?, terminating
En las siguientes pruebas solo vi el comportamiento anterior, pero no vi ningún error en el registro de Mongo.
Cuando se ejecutan estas pruebas, mongo generalmente utiliza aproximadamente el 80 por ciento de la memoria del sistema antes de fallar.
Aquí están las únicas consultas de Mongo utilizadas por este punto final:
utility.getNextId(db, "projects", function(err, counter) {
var pid = counter.seq;
var newProject = {
name: projectName,
path: "/projects/"+user.name+"/"+projectName,
created: utility.now(),
modified: utility.now(),
uid: user.uid,
pid: pid,
ip: ip
}
// Hierarchy of cloned projects
if( parentPid )
newProject.parent = parentPid;
db.collection("projects").insert(newProject, function(err, inserted) {
db.collection("users").update(
{uid: user.uid},
{$addToSet: { projects:pid }},
function(err,_) {
callback(err, newProject);
}
);
});
});
};
exports.getNextId = function(db, name, callback) {
db.collection("counters").findAndModify(
{_id:name},
[["_id","asc"]],
{$inc : {"seq":1}},
{upsert:true, new:true},
function(err, object) {
callback(err, object);
}
);
};
La mayor parte de estas pruebas se realizaron en una amazon ec2 m4.4xlarge (16 cpus y 64GB de RAM).
¿El tamaño de la agrupación de conexiones es de 50 a grande para una máquina con 64 GB de RAM? Yo pensaría que no. ¿Hay una buena manera de calcular la cantidad de memoria necesaria para n grupos de conexiones? ¿Mi problema con las consultas que estoy haciendo?
EDITAR: Aquí hay una captura de pantalla que muestra el derecho del mongostat cuando el mongo se colapsó en el amazon ec2 m4.4xlarge con 16cpus y 64GB de ram.
Creamos el mongo DB en la parte superior con muchos otros requisitos:
var mongo = require("mongodb");
var flash = require("connect-flash");
var session = require("express-session");
var auth = require("basic-auth");
var admin = require("./admin.js");
var mongoServer = new mongo.Server("localhost", 27017, {auto_recconnect:true, poolSize: 50});
var db = new mongo.Db("aqo", mongoServer, {safe:true});
var busboy = require(''connect-busboy'');
db.open(function(err,db) {
if(err)
console.warn("mongo-open err:",err);
});
EDITAR: Aquí están mis índices para la colección de usuarios:
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "aqo.users"
},
{
"v" : 1,
"key" : {
"uid" : 1
},
"name" : "uid_1",
"ns" : "aqo.users"
}
]
Aunque el tamaño de la piscina de 50 no es grande para una máquina con 64 GB de RAM, 800 ciertamente lo es. Esto se debe a que tiene 16 instancias de su proceso de nodo ejecutándose con 50 cada una. El número predeterminado para conexiones máximas es el 80% de los descriptores de archivos disponibles. Si está utilizando Linux, el valor predeterminado es 1024, por lo que ya tiene casi las conexiones máximas abiertas. Además, cada conexión tiene una sobrecarga de ~ 10 MB, por lo que está utilizando alrededor de 8 GB solo para las conexiones. Esto obviamente no es lo ideal.
Idealmente, se supone que debes reutilizar esas conexiones en tu grupo de conexiones tanto como sea posible. Por lo tanto, comience su prueba de carga configurando poolSize con el valor predeterminado de 5. (es decir, 16 * 5 = 80 en realidad). Puede confiar en que pm2 manejará bien la carga de forma rotativa y que el tamaño de la agrupación de 5 para cada instancia debería ser perfectamente correcto y brindarle un rendimiento óptimo. En caso de que 5 no sea suficiente, sube un poco hasta que encuentres algo adecuado.
Tiene una gran cantidad de lecturas en cola y no se realizan muchas lecturas correctamente. Mi conjetura es que el uid
en la colección de users
no tiene un índice (como lo _id
otra parte y Mongo lo indexará automáticamente).
También parece que está ejecutando Mongo como un servidor independiente, está diseñado para ejecutarse como conjuntos de réplicas, no estoy seguro de los problemas que esto causará, pero supongo que no han realizado muchas pruebas en una sola instancia de Mongo trabajando por su cuenta por lo que podría haber problemas de memoria.