[ 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:
-
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.
-
Recyceln Sie Ihre Arbeitsprozesse in regelmäßigen Abständen. Bei einem lang laufenden Prozess summiert sich selbst ein kleines Speicherleck mit der Zeit auf.
-
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.
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? .