711 Stimmen

Node.js auf Multi-Core-Maschinen

Node.js sieht interessant aus, BUT Ich muss etwas übersehen haben - ist Node.js nicht darauf abgestimmt, nur auf einem einzigen Prozess und Thread zu laufen?

Wie skaliert es dann für Multi-Core-CPUs und Multi-CPU-Server? Schließlich ist es großartig, einen möglichst schnellen Single-Thread-Server zu bauen, aber für hohe Lasten würde ich mehrere CPUs verwenden wollen. Und das Gleiche gilt für die Beschleunigung von Anwendungen - anscheinend werden heute mehrere CPUs verwendet und die Aufgaben parallelisiert.

Wie passt Node.js in dieses Bild? Ist es die Idee, mehrere Instanzen irgendwie zu verteilen oder was?

4 Stimmen

Es sieht so aus, als ob Ryah anfängt, sich ernsthaft mit der eingebauten Multi-Core-Unterstützung in Node zu beschäftigen: github.com/joyent/node/commit/

3 Stimmen

Der PM2-Prozessmanager verwendet intern das Clustermodul, um Ihre NodeJS-Anwendungen auf alle verfügbaren Kerne zu verteilen: github.com/Unitech/pm2

1 Stimmen

@broofa, Das sind keine echten Threads und Kindprozesse haben keinen gemeinsamen Speicher. Siehe auch Was ist das Nodejs-Equivalent zu Javas echtem Threading und flüchtigen statischen Variablen? .

777voto

Dave Dopson Punkte 39640

[ Dieser Beitrag ist auf dem Stand vom 2012-09-02 (neuer als oben). ]

Node.js skaliert durchaus auf Multicore-Maschinen.

Ja, Node.js besteht aus einem Thread pro Prozess. Dies ist eine sehr bewusste Design-Entscheidung und eliminiert die Notwendigkeit, sich mit Locking-Semantik zu beschäftigen. Wenn Sie damit nicht einverstanden sind, ist Ihnen wahrscheinlich noch nicht klar, wie wahnsinnig schwer es ist, Multithreading-Code zu debuggen. Für eine tiefere Erklärung des Node.js-Prozessmodells und warum es so funktioniert (und warum es NIE mehrere Threads unterstützen wird), lesen Sie mein anderer Beitrag .

Wie nutze ich also die Vorteile meiner 16-Kern-Box?

Zwei Möglichkeiten:

  • Für große, rechenintensive Aufgaben wie die Bildkodierung kann Node.js Kindprozesse starten oder Nachrichten an zusätzliche Arbeitsprozesse senden. In diesem Design hätten Sie einen Thread, der den Fluss der Ereignisse verwaltet, und N Prozesse, die schwere Rechenaufgaben erledigen und die anderen 15 CPUs beanspruchen.
  • Um den Durchsatz eines Webservices zu skalieren, sollten Sie mehrere Node.js-Server auf einem Rechner betreiben, einen pro Kern, und den Anforderungsverkehr zwischen ihnen aufteilen. Dies bietet eine hervorragende CPU-Affinität und skaliert den Durchsatz nahezu linear mit der Anzahl der Kerne.

Skalierung des Durchsatzes bei einem Webservice

Seit Version 6.0.X enthält Node.js das Clustermodul Das macht es einfach, mehrere Node Worker einzurichten, die an einem einzigen Port lauschen können. Beachten Sie, dass dies NICHT dasselbe ist wie das ältere learnboost-"Cluster"-Modul, das über npm .

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

Die Arbeitnehmer konkurrieren um die Annahme neuer Verbindungen, und der am wenigsten belastete Prozess wird höchstwahrscheinlich gewinnen. Das funktioniert ziemlich gut und kann den Durchsatz auf einem Multi-Core-Rechner recht gut steigern.

Wenn Sie genug Last haben, um sich um mehrere Kerne zu kümmern, dann werden Sie auch ein paar andere Dinge tun wollen:

  1. Führen Sie Ihren Node.js-Dienst hinter einem Web-Proxy wie Nginx o Apache - etwas, das die Verbindung drosseln kann (es sei denn, Sie wollen, dass die Box bei Überlastung komplett ausfällt), URLs umschreiben, statische Inhalte bereitstellen und andere Unterdienste als Proxy nutzen kann.

  2. Recyceln Sie Ihre Arbeitsprozesse in regelmäßigen Abständen. Bei einem lang laufenden Prozess summiert sich selbst ein kleines Speicherleck mit der Zeit auf.

  3. Protokollerfassung/Überwachung einrichten


PS: Es gibt eine Diskussion zwischen Aaron und Christopher in den Kommentaren eines anderen Beitrags (zum Zeitpunkt der Erstellung dieses Artikels ist es der oberste Beitrag). Ein paar Kommentare dazu:

  • Ein Shared-Socket-Modell ist sehr praktisch, um mehreren Prozessen die Möglichkeit zu geben, an einem einzigen Port zu lauschen und um die Annahme neuer Verbindungen zu konkurrieren. Vom Konzept her könnte man sich vorstellen, dass ein vorgefertigter Apache dies tut, allerdings mit dem bedeutenden Vorbehalt, dass jeder Prozess nur eine einzige Verbindung akzeptiert und dann stirbt. Der Effizienzverlust für den Apache liegt im Overhead des Forkens neuer Prozesse und hat nichts mit den Socketoperationen zu tun.
  • Für Node.js ist es eine äußerst vernünftige Lösung, N Worker auf einem einzigen Socket konkurrieren zu lassen. Die Alternative besteht darin, ein On-Box-Frontend wie Nginx einzurichten, das den Datenverkehr an die einzelnen Worker weiterleitet und abwechselnd neue Verbindungen zuweist. Diese beiden Lösungen haben sehr ähnliche Leistungsmerkmale. Und da Sie, wie ich oben erwähnt habe, wahrscheinlich sowieso Nginx (oder eine Alternative) als Front-End für Ihren Node-Service verwenden möchten, müssen Sie sich hier wirklich entscheiden:

Gemeinsame Häfen: nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)

gegen

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

Die Einrichtung einzelner Ports hat wohl einige Vorteile (geringere Kopplung zwischen Prozessen, ausgefeiltere Lastausgleichsentscheidungen usw.), ist aber definitiv aufwändiger, und das eingebaute Clustermodul ist eine Alternative mit geringerer Komplexität, die für die meisten Benutzer geeignet ist.

49voto

Chandra Sekar Punkte 10483

Eine Methode wäre, mehrere Instanzen von node.js auf dem Server laufen zu lassen und dann einen Load Balancer (vorzugsweise einen nicht-blockierenden wie nginx) davor zu setzen.

34voto

broofa Punkte 36174

Ryan Dahl beantwortet diese Frage in den technischen Vortrag, den er bei Google gehalten hat letzten Sommer. Um es mit den Worten zu sagen: "Führen Sie einfach mehrere Knotenprozesse aus und verwenden Sie etwas Vernünftiges, um ihnen die Kommunikation zu ermöglichen, z.B. IPC im Stil von sendmsg() oder traditionelles RPC".

Wenn Sie sich sofort die Hände schmutzig machen wollen, sollten Sie sich die ~~Funke2 Für immer Modul. Es macht das Erzeugen von mehreren Knotenprozessen trivial einfach. Es kümmert sich um die Einrichtung der gemeinsamen Nutzung von Ports, so dass jeder von ihnen Verbindungen zum selben Port akzeptieren kann, und auch um das Auto-Respawning, wenn Sie sicherstellen wollen, dass ein Prozess neu gestartet wird, wenn er stirbt.~~

AKTUALISIERUNG - 10/11/11 : In der Knotenpunkt-Gemeinschaft scheint man sich einig zu sein, dass Cluster ist jetzt das bevorzugte Modul für die Verwaltung mehrerer Knoteninstanzen pro Rechner. Für immer ist ebenfalls einen Blick wert.

31voto

Sergey Zhukov Punkte 644

Sie können verwenden Cluster Modul. Prüfen Sie diese .

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);
}

19voto

Toumi Punkte 2536

Node Js unterstützt Clustering, um die Vorteile des Prozessors voll auszunutzen. Wenn Sie es nicht mit Cluster laufen lassen, dann verschwenden Sie wahrscheinlich Ihre Hardwarekapazitäten.

Clustering in Node.js ermöglicht es Ihnen, separate Prozesse zu erstellen, die sich denselben Server-Port teilen können. Wenn wir zum Beispiel einen HTTP-Server auf Port 3000 laufen lassen, handelt es sich um einen Server, der auf einem einzelnen Thread auf einem einzelnen Prozessorkern läuft.

Der unten gezeigte Code ermöglicht es Ihnen, Ihre Anwendung zu clustern. Dieser Code ist offizieller Code von Node.js dargestellt.

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.
}

In diesem Artikel finden Sie die vollständige Lehrgang

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X