659 votes

Node.js sur les machines multi-cœurs

Node.js semble intéressant, MAIS Je dois manquer quelque chose - Node.js n'est-il pas réglé pour fonctionner sur un seul processus et un seul fil ?

Alors comment s'adapte-t-elle aux processeurs multi-cœurs et aux serveurs multi-CPU ? Après tout, c'est très bien de faire un serveur aussi rapide que possible avec un seul thread, mais pour les charges élevées, je voudrais utiliser plusieurs CPU. Il en va de même pour l'accélération des applications. Il semble qu'aujourd'hui, la solution consiste à utiliser plusieurs processeurs et à paralléliser les tâches.

Comment Node.js s'intègre-t-il dans ce tableau ? Son idée est-elle de distribuer d'une manière ou d'une autre des instances multiples ou quoi ?

4 votes

Il semble que Ryah commence à prendre au sérieux l'inclusion d'un support multi-core intégré dans node : github.com/joyent/node/commit/

3 votes

Le gestionnaire de processus PM2 utilise le module cluster en interne pour répartir vos applications NodeJS sur tous les cœurs disponibles : github.com/Unitech/pm2

1 votes

@broofa, Ce ne sont pas de vrais threads et les processus enfants n'ont pas de mémoire partagée. Voir aussi Quel est l'équivalent pour Nodejs du threading réel et des variables volatiles-statiques de Java ? .

737voto

Dave Dopson Points 16690

[ Ce billet est à jour en date du 2012-09-02 (plus récent que ci-dessus). ]

Node.js s'adapte parfaitement aux machines multi-cœurs.

Oui, Node.js est un thread par processus. Il s'agit d'une décision de conception très délibérée qui élimine le besoin de gérer la sémantique du verrouillage. Si vous n'êtes pas d'accord avec cela, vous ne réalisez probablement pas encore à quel point il est difficile de déboguer un code multithread. Pour une explication plus approfondie du modèle de processus de Node.js et de la raison pour laquelle il fonctionne de cette façon (et pourquoi il ne supportera JAMAIS les threads multiples), lisez le document suivant mon autre poste .

Alors, comment puis-je tirer parti de ma boîte à 16 noyaux ?

De deux façons :

  • Pour les grosses tâches de calcul lourd comme le codage d'images, Node.js peut lancer des processus enfants ou envoyer des messages à des processus travailleurs supplémentaires. Dans cette conception, vous auriez un thread gérant le flux d'événements et N processus effectuant des tâches de calcul lourdes et dévorant les 15 autres CPU.
  • Pour mettre à l'échelle le débit d'un service Web, vous devriez exécuter plusieurs serveurs Node.js sur une boîte, un par cœur, et répartir le trafic des demandes entre eux. Cela permet d'obtenir une excellente affinité avec le CPU et de faire évoluer le débit de façon presque linéaire avec le nombre de cœurs.

Mise à l'échelle du débit d'un service web

Depuis la version 6.0.X, Node.js a inclus le module cluster ce qui facilite la mise en place de plusieurs nœuds travailleurs qui peuvent écouter sur un seul port. Notez que ce n'est PAS la même chose que l'ancien module "cluster" de learnboost disponible par le biais de 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 seront en concurrence pour accepter de nouvelles connexions, et le processus le moins chargé a le plus de chances de l'emporter. Cela fonctionne plutôt bien et peut augmenter le débit sur une machine multi-core.

Si vous avez une charge suffisante pour vous préoccuper de plusieurs cœurs, vous allez vouloir faire un peu plus de choses aussi :

  1. Exécutez votre service Node.js derrière un proxy web tel que Nginx ou Apache - quelque chose qui peut limiter les connexions (à moins que vous ne souhaitiez que les conditions de surcharge fassent complètement tomber la boîte), réécrire les URL, servir du contenu statique et mettre en place d'autres sous-services.

  2. Recyclez périodiquement vos processus de travail. Pour un processus qui tourne depuis longtemps, même une petite fuite de mémoire finit par s'accumuler.

  3. Configuration de la collecte et de la surveillance des journaux


PS : Il y a une discussion entre Aaron et Christopher dans les commentaires d'un autre article (à l'heure où j'écris ces lignes, c'est l'article le plus important). Quelques commentaires à ce sujet :

  • Un modèle de socket partagé est très pratique pour permettre à plusieurs processus d'écouter sur un même port et de se faire concurrence pour accepter de nouvelles connexions. D'un point de vue conceptuel, on pourrait penser qu'Apache préfourché fait cela, avec la réserve importante que chaque processus n'acceptera qu'une seule connexion et mourra ensuite. La perte d'efficacité d'Apache se situe au niveau des frais généraux liés à la création de nouveaux processus et n'a rien à voir avec les opérations sur les sockets.
  • Pour Node.js, avoir N travailleurs en concurrence sur un seul socket est une solution extrêmement raisonnable. L'autre solution consiste à mettre en place un front-end intégré comme Nginx et à faire en sorte que le trafic soit acheminé par proxy vers les différents workers, en alternant entre les workers pour l'attribution de nouvelles connexions. Ces deux solutions présentent des caractéristiques de performance très similaires. Et puisque, comme je l'ai mentionné ci-dessus, vous voudrez probablement avoir Nginx (ou une alternative) en tête de votre service de nœuds de toute façon, le choix ici est vraiment entre :

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

vs

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

Il y a sans doute quelques avantages à la configuration des ports individuels (possibilité d'avoir moins de couplage entre les processus, d'avoir des décisions d'équilibrage de charge plus sophistiquées, etc.), mais c'est définitivement plus de travail à mettre en place et le module cluster intégré est une alternative peu complexe qui fonctionne pour la plupart des gens.

2 votes

Pouvez-vous donner des conseils pour exécuter différents services basés sur nodejs sur une seule machine ? Par exemple, disons que j'ai un serveur, et que je veux exécuter myservice1.js sur CpuCore1, et myservice2.js sur CpuCore2. Puis-je utiliser un cluster pour cela ? ou est-ce seulement utile pour créer des services clonés ?

7 votes

Vous devriez poster une question à ce sujet ! (et je copierai ce commentaire comme votre première réponse). Ce que vous voulez faire est en fait très simple. Vous n'auriez pas vraiment besoin de "cluster", vous auriez juste à exécuter deux services de nœuds différents. Deux scripts, deux processus, deux ports. Par exemple, vous pourriez avoir le serviceA qui écoute sur 3000 et le serviceB qui écoute sur 3001. Chacun de ces services pourrait utiliser "cluster" pour avoir 1+ travailleurs et les recycler périodiquement, etc. Vous pourriez ensuite configurer Nginx pour qu'il écoute sur le port 80 et qu'il redirige vers le bon service en fonction de l'en-tête "Host" entrant et/ou du chemin URL.

1 votes

Merci. J'ai a posté une question connexe déjà - vous avez décrit à peu près ce que j'avais à l'esprit, mais je ne suis pas sûr de la façon de cibler les cœurs du CPU (en utilisant quelque chose comme forever).

81voto

Aaron Digulla Points 143830

(Je ne peux pas supprimer cette réponse, mais elle est périmée, maintenant. Pour une réponse plus détaillée, voir celle de Dave Dopson ci-dessous).

Node.js ne prend pas en charge les processeurs multiples dès le départ, comme le montre la page Web :

Mais qu'en est-il de la concurrence entre plusieurs processeurs ? Les threads sont nécessaires pour adapter les programmes aux ordinateurs multi-cœurs. Les processus sont nécessaires pour s'adapter aux ordinateurs multi-cœurs, pas les threads qui partagent la mémoire. Les principes de base des systèmes évolutifs sont la mise en réseau rapide et la conception non bloquante - le reste n'est que du passage de messages. Dans les futures versions, Node.js sera capable de forker de nouveaux processus (en utilisant l'API Web Workers), mais c'est quelque chose qui s'intègre bien dans la conception actuelle.

Mais vous pouvez toujours utiliser les autres cœurs ; vous devez simplement écrire plus de code. Ce n'est pas quelque chose que Node.js fera automatiquement pour vous. D'un point de vue positif, cela vous donne plus de contrôle.

47voto

Chandru Points 4770

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

37 votes

Node.js est à peu près aussi rapide que nginx, vous pourriez mettre un équilibreur de charge node.js devant vos serveurs node.js si vous le vouliez également :)

26 votes

Ryan a spécifiquement dit de ne pas faire ça avant que le Node soit plus stable. Le meilleur moyen est d'exécuter nginx en face de node.

2 votes

Quant à nginx devant node, il ne résoudra pas certains problèmes comme si vous avez une file d'attente en mémoire. Les instances de 2 nœuds ne pourront pas accéder à la file d'attente de l'autre.

31voto

broofa Points 21663

Ryan Dahl répond à cette question dans la conférence technique qu'il a donnée à Google l'été dernier. Pour paraphraser, "il suffit d'exécuter plusieurs processus de nœuds et d'utiliser quelque chose de sensé pour leur permettre de communiquer, par exemple un IPC de type sendmsg() ou un RPC traditionnel".

Si vous voulez vous salir les mains tout de suite, allez voir la ~~étincelle2 Forever module. Il rend la création de processus de nœuds multiples trivialement facile. Il gère la mise en place du partage de port, de sorte qu'ils puissent chacun accepter des connexions sur le même port, et aussi l'auto-respawning si vous voulez vous assurer qu'un processus est redémarré si/quand il meurt.~~

MISE À JOUR - 10/11/11 : Le consensus dans la communauté des noeuds semble être que Cluster est désormais le module privilégié pour gérer plusieurs instances de nœuds par machine. Forever vaut également le coup d'œil.

9 votes

Forever et Cluster font des choses très différentes. Vous pouvez même utiliser les deux. Forever redémarre un processus lorsqu'il meurt. Cluster gère plusieurs travailleurs. Vous utiliserez Forever pour gérer votre processus maître...

4 votes

De plus, le module learnboost est largement supplanté par la version de Cluster intégrée à Node v0.6.x (attention : la surface de l'API est différente).

0 votes

@broofa Comment est l'IPC par défaut comparé à, disons, l'utilisation de Redis ou Memcache en envoyant simplement des chaînes/données/rays entre les processus ? Quelle méthode serait la plus rapide ?

13voto

CyberFonic Points 2218

Le multi-nœud exploite tous les noyaux que vous pouvez avoir.
Jetez un coup d'œil à http://github.com/kriszyp/multi-node .

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X