web-dev-qa-db-fra.com

Node.js sur des machines multi-core

Node.js semble intéressant, MAIS Je dois rater quelque chose - Node.js n'est pas à l'écoute pour fonctionner uniquement un seul processus et thread?

Alors, comment évolue-t-il pour les CPU multi-core et les serveurs multi-CPU? Après tout, il est bon de rendre aussi rapide que possible le serveur mono-thread, mais pour des charges élevées, je voudrais utiliser plusieurs processeurs. Et il en va de même pour rendre les applications plus rapides - il semble aujourd'hui que l'on utilise plusieurs processeurs et parallélise les tâches.

Comment Node.js s'intègre-t-il dans cette image? Son idée est-elle de distribuer en quelque sorte plusieurs instances ou quoi?

567
zaharpopov

[ Ce message est à jour du 12/09/2012 (plus récent que précédemment). ]

Node.js s'adapte parfaitement aux machines multicœurs.

Oui, Node.js est un thread par processus. C'est une décision de conception très délibérée qui élimine la nécessité de traiter avec la sémantique de verrouillage. Si vous n'êtes pas d'accord avec cela, vous ne réalisez probablement pas encore à quel point il est incroyablement difficile de déboguer du code multi-thread. Pour une explication plus détaillée du modèle de processus Node.js et de la raison pour laquelle il fonctionne de cette façon (et pourquoi il ne supportera JAMAIS plusieurs threads), lisez mon autre message .

Alors, comment puis-je profiter de ma boîte de 16 cœurs?

Deux façons:

  • Node.js peut déclencher des processus enfants ou envoyer des messages à des processus de travail supplémentaires pour les tâches de calcul lourdes telles que le codage d'image. Dans cette conception, vous auriez un thread qui gérera le flux d’événements et N processus qui effectueront des tâches de calcul lourdes et mordilleront les 15 autres processeurs.
  • Pour adapter le débit sur un service Web, vous devez exécuter plusieurs serveurs Node.js sur un boîtier, un par cœur, et répartir le trafic des requêtes entre eux. Ceci fournit une excellente affinité pour le processeur et permet d’adapter le débit presque linéairement au nombre de cœurs.

Mise à l'échelle du débit sur un service Web

Depuis la v6.0.X, Node.js a inclus le module de cluster directement, ce qui facilite la configuration de plusieurs opérateurs de nœuds pouvant écouter sur un seul port. Notez que ce n'est pas la même chose que l'ancien module "cluster" de learnboost disponible via npm .

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  http.Server(function(req, res) { ... }).listen(8000);
}

Les travailleurs se feront concurrence pour accepter de nouvelles connexions et le processus le moins chargé gagnera probablement. Cela fonctionne plutôt bien et peut très bien augmenter le débit sur une boîte multicœur.

Si vous avez suffisamment de charge pour vous préoccuper de plusieurs cœurs, vous voudrez également faire quelques tâches supplémentaires:

  1. Exécutez votre service Node.js derrière un proxy Web tel que Nginx ou Apache - quelque chose qui peut limiter la connexion (sauf si vous souhaitez que les conditions de surcharge réduisent complètement la boîte), réécrire les URL, servir le contenu statique et proxy d'autres sous-services.

  2. Recyclez périodiquement vos processus de travail. Pour un processus de longue durée, même une petite fuite de mémoire finira par s’additionner.

  3. Configuration du journal de collecte/surveillance


PS: Il y a une discussion entre Aaron et Christopher dans les commentaires d'un autre post (au moment d'écrire ces lignes, c'est le post le plus haut). Quelques commentaires à ce sujet:

  • Un modèle de socket partagé est très pratique pour permettre à plusieurs processus d'écouter sur un seul port et d'entrer en concurrence pour accepter de nouvelles connexions. D'un point de vue conceptuel, vous pourriez penser à Apache préformé en procédant de la sorte, avec l'avertissement important que chaque processus n'acceptera qu'une seule connexion, puis mourra. La perte d'efficacité pour Apache est due à la surcharge de nouveaux processus et n'a rien à voir avec les opérations de socket.
  • Pour Node.js, avoir N travailleurs en concurrence sur un seul socket est une solution extrêmement raisonnable. L’autre solution consiste à configurer un serveur frontal tel que Nginx et à affecter ce trafic proxy aux travailleurs individuels, en alternant les travailleurs pour l’attribution de nouvelles connexions. Les deux solutions présentent des caractéristiques de performance très similaires. Et comme, comme je l’ai mentionné ci-dessus, vous souhaiterez probablement que Nginx (ou une alternative) s’occupe de toute façon de votre service de nœud, le choix est vraiment entre:

Ports partagés: nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)

contre

Ports individuels: nginx (port 80) --> {Node_worker (port 3000), Node_worker (port 3001), Node_worker (port 3002), Node_worker (port 3003) ...}

Il existe certes des avantages pour la configuration des ports individuels (possibilité d’avoir moins de couplage entre les processus, des décisions plus complexes en matière d’équilibrage de la charge, etc.), mais il est nettement plus fastidieux de le configurer et le module de cluster intégré est faible. -complexité alternative qui fonctionne pour la plupart des gens.

671
Dave Dopson

Une méthode consiste à exécuter plusieurs instances de node.js sur le serveur, puis à leur placer un équilibreur de charge (de préférence non bloquant, tel que nginx).

41
Chandra Sekar

Ryan Dahl répond à cette question dans la conférence technique qu'il a donnée à Google l'été dernier. Pour paraphraser, "exécutez simplement plusieurs processus de noeud et utilisez quelque chose de sensé pour leur permettre de communiquer. Par exemple, sendmsg () - style IPC ou un RPC traditionnel".

Si vous voulez vous salir les mains immédiatement, consultez le spark2 Pour toujours module. Cela facilite trivialement la création de processus à plusieurs nœuds. Il gère la configuration du partage de port, afin qu'ils puissent chacun accepter les connexions au même port, ainsi que la création automatique si vous voulez vous assurer qu'un processus est redémarré si/quand il meurt.

UPDATE - 10/11/11 : Le consensus dans la communauté des nœuds semble être que Cluster est maintenant le module préféré pour la gestion plusieurs instances de nœud par machine. Forever vaut également le coup d'oeil.

30
broofa

Vous pouvez utiliser le module cluster . Vérifiez this .

var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    // Fork workers.
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {
    // Workers can share any TCP connection
    // In this case its a HTTP server
    http.createServer(function(req, res) {
        res.writeHead(200);
        res.end("hello world\n");
    }).listen(8000);
}
17
Sergey Zhukov

Multi-nœud exploite tous les cœurs que vous pourriez avoir.
Regardez http://github.com/kriszyp/multi-node .

Pour des besoins plus simples, vous pouvez démarrer plusieurs copies de nœud sur différents numéros de port et placer un équilibreur de charge devant eux.

13
CyberFonic

Comme mentionné ci-dessus, Cluster redimensionnera et équilibrera la charge de votre application sur tous les cœurs.

ajouter quelque chose comme

cluster.on('exit', function () {
  cluster.fork();
});

Va redémarrer tous les travailleurs défaillants.

De nos jours, beaucoup de gens préfèrent également PM2 , qui gère la mise en cluster pour vous et fournit également quelques fonctionnalités de surveillance intéressantes .

Ajoutez ensuite Nginx ou HAProxy devant plusieurs machines fonctionnant en cluster. Vous disposez ainsi de plusieurs niveaux de basculement et d'une capacité de charge bien supérieure.

10
Will Stern

Node Js prend en charge la mise en cluster pour tirer pleinement parti de votre processeur. Si vous ne l'exécutez pas avec un cluster, vous gaspillez probablement vos capacités matérielles.

La mise en cluster dans Node.js vous permet de créer des processus distincts pouvant partager le même port de serveur. Par exemple, si nous exécutons un serveur HTTP sur le port 3000, il s’agit d’un serveur exécuté sur un seul thread sur un seul cœur de processeur.

Le code ci-dessous vous permet de regrouper votre application. Ce code est le code officiel représenté par Node.js.

var cluster = require('cluster');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    // Fork workers.
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    Object.keys(cluster.workers).forEach(function(id) {
        console.log("I am running with ID : " + cluster.workers[id].process.pid);
    });

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {

    //Do further processing.
}

vérifier cet article pour le plein tutoriel

8
Toumi

La prochaine version de node vous permettra de bifurquer un processus et de lui transmettre des messages. Ryan a déclaré qu'il souhaitait trouver un moyen de partager également les gestionnaires de fichiers. Il ne s'agira donc pas d'une implémentation Web Worker simple.

Pour le moment, il n’ya pas de solution facile à cela, mais il est encore très tôt et node est l’un des projets open source les plus rapides et les plus mobiles que je n’ai jamais vus.

7
mikeal

Spark2 est basé sur Spark qui n'est plus maintenu. Cluster est son successeur et présente quelques fonctionnalités intéressantes, telles que la création d'un processus de travail par cœur de processeur et le rétablissement des travailleurs morts.

7
TheDeveloper

Le nouveau venu ici est LearnBoost "Up" .

Il fournit des "recharges zéro temps d'arrêt" et crée en outre plusieurs travailleurs (par défaut, le nombre de processeurs, mais il est configurable) pour fournir le meilleur des mondes.

C'est nouveau, mais semble être assez stable, et je l'utilise avec bonheur dans l'un de mes projets en cours.

5
Roy

J'utilise Node worker pour exécuter des processus de manière simple à partir de mon processus principal. Semble fonctionner très bien pendant que nous attendons la voie officielle.

5
christkv

Le module cluster vous permet d'utiliser tous les cœurs de votre machine. En fait, vous pouvez en profiter en seulement 2 commandes et sans toucher votre code en utilisant un très populaire gestionnaire de processus pm2 .

npm i -g pm2
pm2 start app.js -i max
2
Alister

Vous pouvez exécuter votre application node.js sur plusieurs cœurs en utilisant le module cluster en combinaison avec le module os , qui peut être utilisé pour détecter le nombre de CPU dont vous disposez.

Par exemple, imaginons que vous avez un module server qui exécute un serveur http simple sur le backend et que vous voulez l'exécuter pour plusieurs processeurs:

// Dependencies.
const server = require('./lib/server'); // This is our custom server module.
const cluster = require('cluster');
const os = require('os');

 // If we're on the master thread start the forks.
if (cluster.isMaster) {
  // Fork the process.
  for (let i = 0; i < os.cpus().length; i++) {
    cluster.fork();
  }
} else {
  // If we're not on the master thread start the server.
  server.init();
}
1
Oleksii Trekhleb

Il est possible de faire évoluer NodeJS vers plusieurs boîtes en utilisant un équilibreur de charge pur TCP (HAProxy) devant plusieurs boîtes exécutant un processus NodeJS chacune.

Si vous avez des connaissances communes à partager entre toutes les instances, vous pouvez utiliser un magasin Redis central ou similaire, accessible depuis toutes les instances de processus (par exemple, depuis toutes les boîtes).

0
Martin Tajur

Il est également possible de concevoir le service Web sous la forme de plusieurs serveurs autonomes écoutant des sockets Unix, de sorte que vous puissiez transférer des fonctions telles que le traitement des données dans des processus distincts.

Ceci est similaire à la plupart des architectures de serveur Web de scrpting/base de données dans lesquelles un processus cgi gère la logique métier, puis transfère et extrait les données via une socket Unix vers une base de données.

la différence étant que le traitement des données est écrit en tant que nœud de serveur Web à l'écoute sur un port.

c'est plus complexe, mais au final, c'est vers le développement multicœur. une architecture multiprocessus utilisant plusieurs composants pour chaque requête Web.

0
Fire Crow