Voici ce que je suis en train de faire: je suis l'élaboration d'un Node.js serveur http, qui tiendra longtemps connexions pour pousser but(collaboration avec le redis) à partir de dizaines de milliers de clients mobiles en une seule machine.
Environnement de Test:
1.80GHz*2 CPU/2GB RAM/Unbuntu12.04/Node.js 0.8.16
Pour la première fois, j'ai utilisé "express" du module, avec qui j'ai pu atteindre environ 120k connexions simultanées avant de swap utilisé ce qui signifie que la RAM n'est pas assez. Ensuite, je suis passé à la maternelle "http" du module, j'ai eu la simultanéité jusqu'à environ 160k. Mais j'ai réalisé qu'il y a encore beaucoup trop de fonctionnalités je n'ai pas besoin d'en natif http module, donc je suis passé natif "net" module(ce qui signifie que j'ai besoin de gérer le protocole http par moi-même, mais c'est ok). maintenant, je peux atteindre environ 250 connexions simultanées par une seule machine.
Ici est la principale structure de mes codes:
var net = require('net');
var redis = require('redis');
var pendingClients = {};
var redisClient = redis.createClient(26379, 'localhost');
redisClient.on('message', function (channel, message) {
var client = pendingClients[channel];
if (client) {
client.res.write(message);
}
});
var server = net.createServer(function (socket) {
var buffer = '';
socket.setEncoding('utf-8');
socket.on('data', onData);
function onData(chunk) {
buffer += chunk;
// Parse request data.
// ...
if ('I have got all I need') {
socket.removeListener('data', onData);
var req = {
clientId: 'whatever'
};
var res = new ServerResponse(socket);
server.emit('request', req, res);
}
}
});
server.on('request', function (req, res) {
if (res.socket.destroyed) {
return;
}
pendingClinets[req.clientId] = {
res: res
};
redisClient.subscribe(req.clientId);
res.socket.on('error', function (err) {
console.log(err);
});
res.socket.on('close', function () {
delete pendingClients[req.clientId];
redisClient.unsubscribe(req.clientId);
});
});
server.listen(3000);
function ServerResponse(socket) {
this.socket = socket;
}
ServerResponse.prototype.write = function(data) {
this.socket.write(data);
}
Enfin, voici mes questions:
Comment puis-je réduire l'utilisation de la mémoire, de sorte que l'augmentation de la simultanéité plus loin?
Je suis vraiment confus sur la façon de calculer l'utilisation de la mémoire de Node.js processus. Je sais Node.js alimenté par Chrome V8, il est processus.memoryUsage() de l'api et de retour de trois valeurs: rss/heapTotal/heapUsed, quelle est la différence entre eux, la partie de qui dois-je préoccupation de plus, et ce qui est exactement la composition de la mémoire utilisée par le Node.js processus?
Je me suis inquiété de fuite de mémoire, même si j'ai fait quelques tests et il ne semble pas être un problème. Existe-il des points que je doit concerner tout ou conseille?
J'ai trouvé une doc sur les V8 classe caché, comme il le décrit, est-ce à dire chaque fois que j'ajoute une propriété nommée par clientId à mon objet global pendingClients tout comme mes codes ci-dessus, il y aura une nouvelle classe cachée être générée? Dose, il sera la cause de fuite de mémoire?
J'ai utilisé webkit-devtools-agent pour analyser les tas de carte de la Node.js processus. J'ai commencé le processus et a pris un instantané du tas, puis j'ai envoyé 10k demandes et déconnecté plus tard, après que j'ai pris un tas instantané de nouveau. J'ai utilisé la comparaison de la perspective de voir la différence entre ces deux clichés. Voici ce que j'ai: Quelqu'un pourrait-il m'expliquer cela? Le nombre et la taille de l' (tableau)/(code compilé)/(string)/Commande/Tableau a beaucoup augmenté, ce qui signifie quoi?
EDIT:
Comment ai-je exécuter l'essai de chargement?
1. Tout d'abord, j'ai modifié certains paramètres à la fois sur la machine serveur et les ordinateurs clients(pour atteindre plus de 60k simultanéité besoin de plus d'une machine client, car une machine seulement 60k+ ports(représenté par 16 bits) au plus)
1.1. À la fois le serveur et le client machines, j'ai modifié le fichier descripteur de l'utilisation de ces commandes dans le shell dans lequel le programme sera exécuté dans:
ulimit -Hn 999999
ulimit -Sn 999999
1.2. Sur la machine serveur, j'ai aussi modifié quelques net/tcp liées paramètres du noyau, les plus importants sont:
net.ipv4.tcp_mem = 786432 1048576 26777216
net.ipv4.tcp_rmem = 4096 16384 33554432
net.ipv4.tcp_wmem = 4096 16384 33554432
1.3. Comme pour les machines clientes:
net.ipv4.ip_local_port_range = 1024 65535
2. Deuxièmement, j'ai écrit une coutume simuler programme client à l'aide de Node.js puisque la plupart des outils de test de charge, ab, siège, etc, sont à court de connexions, mais je suis sur de longues connexions et ont des besoins particuliers.
3. Puis j'ai commencé le programme serveur sur une seule machine, et trois programme client sur les trois autres machines séparées.
EDIT: J'ai fait parvenir à 250 connexions simultanées sur une même machine(2 go de RAM), mais s'est avéré, il n'est pas très significative et pratique. Parce que lorsqu'une connexion connecté, je viens de laisser la connexion en attente, rien d'autre. Quand j'ai essayé d'envoyé de réponse, la simultanéité nombre est tombé à 150 environ. Comme je l'ai calculé, il y a environ 4 KO de plus l'utilisation de la mémoire par connexion, je suppose que c'est lié à net.ipv4.tcp_wmem que j'ai mis à 4096 16384 33554432, mais même je l'ai modifié pour les petits, rien n'a changé. Je ne peux pas comprendre pourquoi.
EDIT: En fait, maintenant, je suis plus intéressé par la quantité de mémoire utilisée par connexion tcp utilise et ce qui est exactement la composition de la mémoire utilisée par une seule connexion? Selon mes données de test:
150k simultanéité consommé environ 1800M de RAM(de libre -m sortie), et la Node.js le processus a environ 600M RSS
Ensuite, j'ai pris ceci:
(1800M - 600M) / 150 = 8k, c'est le noyau de la pile TCP utilisation de la mémoire d'un unique de connexion, il se compose de deux parties: la mémoire tampon de lecture(4 KO) + tampon d'écriture(4 KO)(en Fait, cela ne correspond pas à mon milieu de net.ipv4.tcp_rmem et net.ipv4.tcp_wmem ci-dessus, comment fait-on pour déterminer la quantité de mémoire à utiliser pour ces tampons?)
600M / 150 k = 4k, c'est le Node.js l'utilisation de la mémoire d'une connexion unique
Suis-je le droit? Comment puis-je réduire l'utilisation de la mémoire dans les deux aspects?
Si il y a n'importe où, je n'ai pas décrire le bien, laissez-moi savoir, je vais affiner! Toutes les explications ou des conseils seront les bienvenus, merci!