Node.js su macchine multi-core

Node.js sembra interessante, ma devo perdere qualcosa – non è Node.js sintonizzato solo per essere eseguito su un singolo processo e thread?

Allora come scala per CPU multi-core e server multi-CPU? Dopotutto, è fantastico creare un server single-thread il più veloce ansible, ma per carichi elevati vorrei utilizzare diverse CPU. E lo stesso vale per rendere le applicazioni più veloci – sembra che oggi il modo sia utilizzare più CPU e parallelizzare le attività.

Come si inserisce Node.js in questa immagine? La sua idea è di distribuire in qualche modo più istanze o cosa?

[ Questo post è aggiornato dal 2012-09-02 (più recente di quello sopra). ]

Node.js è assolutamente scalabile su macchine multi-core.

Sì, Node.js è un thread-per-processo. Questa è una decisione progettuale molto deliberata ed elimina la necessità di gestire la semantica di chiusura. Se non sei d’accordo, probabilmente non ti rendi conto di quanto sia faticosamente difficile eseguire il debug del codice multi-thread. Per una spiegazione più approfondita del modello di processo Node.js e perché funziona in questo modo (e perché non supporterà MAI più thread), leggi il mio altro post .

Quindi, come posso sfruttare il mio box 16 core?

Due strade:

  • Per le grandi attività di elaborazione pesanti come la codifica delle immagini, Node.js può triggersre processi figlio o inviare messaggi a processi di lavoro aggiuntivi. In questo progetto, avresti un thread che gestisce il stream di eventi e N processi che eseguono pesanti attività di elaborazione e che masticano le altre 15 CPU.
  • Per ridimensionare il throughput su un servizio web, è necessario eseguire più server Node.js su una casella, uno per il core e il traffico di richieste divise tra loro. Ciò fornisce un’affinità CPU eccellente e scalerà il throughput in modo quasi lineare con il core count.

Scalabilità del throughput su un webservice

Dal momento che v6.0.X Node.js ha incluso il modulo cluster immediatamente fuori dalla scatola, il che semplifica la configurazione di più nodes che possono ascoltare su una singola porta. Si noti che questo NON è uguale al precedente modulo “cluster” learnboost disponibile tramite npm .

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

I lavoratori competeranno per accettare nuove connessioni, e il processo meno caricato ha più probabilità di vincere. Funziona abbastanza bene e può scalare abbastanza bene il throughput su un box multi-core.

Se hai abbastanza carico per preoccuparti di più core, allora vorrai fare ancora un paio di cose:

  1. Esegui il tuo servizio Node.js dietro un proxy web come Nginx o Apache - qualcosa che può fare il throttling della connessione (a meno che non vuoi che le condizioni di sovraccarico riducano completamente la scatola), riscrivi gli URL, serva contenuti statici e proxy altri sotto-servizi.

  2. Ricicli periodicamente i tuoi processi di lavoro. Per un processo di lunga durata, anche una piccola perdita di memoria si sommerà.

  3. Raccolta / monitoraggio del registro di installazione


PS: C'è una discussione tra Aaron e Christopher nei commenti di un altro post (al momento in cui scrivo, è il primo post). Alcuni commenti su questo:

  • Un modello di socket condiviso è molto conveniente per consentire a più processi di ascoltare su una singola porta e competere per accettare nuove connessioni. Concettualmente, si potrebbe pensare ad Apache preforked facendo questo con l'avvertimento significativo che ogni processo accetterà solo una singola connessione e quindi morirà. La perdita di efficienza per Apache è nel sovraccarico di forking di nuovi processi e non ha nulla a che fare con le operazioni di socket.
  • Per Node.js, avere N lavoratori in competizione su un singolo socket è una soluzione estremamente ragionevole. L'alternativa è impostare un front-end on-box come Nginx e avere quel traffico proxy per i singoli lavoratori, alternando i lavoratori per l'assegnazione di nuove connessioni. Le due soluzioni hanno caratteristiche prestazionali molto simili. E dal momento che, come ho detto sopra, probabilmente vorrai avere Nginx (o un'alternativa) per far fronte al tuo servizio di nodo in ogni caso, la scelta qui è davvero tra:

Porte condivise: nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)

vs

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

Ci sono probabilmente alcuni vantaggi per l'impostazione dei singoli porti (possibilità di avere meno accoppiamenti tra processi, avere decisioni di bilanciamento del carico più sofisticate, ecc.), Ma è sicuramente più lavoro da impostare e il modulo cluster incorporato è un basso -complessità alternativa che funziona per la maggior parte delle persone.

Un metodo sarebbe quello di eseguire più istanze di node.js sul server e quindi mettere un bilanciatore del carico (preferibilmente uno non bloccante come nginx) di fronte a loro.

Ryan Dahl risponde a questa domanda nel discorso tecnico che ha dato a Google la scorsa estate. Per parafrasare, “basta eseguire più processi di nodo e utilizzare qualcosa di sensato per consentire loro di comunicare, ad esempio sendmsg () – stile IPC o RPC tradizionale”.

Se vuoi sporcarti le mani, controlla il modulo spark2 Forever . Rende banane le operazioni di spawning di più nodes. Gestisce la condivisione delle porte, in modo che ciascuno possa accettare connessioni alla stessa porta e anche auto-respawning se si desidera assicurarsi che un processo venga riavviato se / quando muore.

AGGIORNAMENTO – 10/11/11 : Il consenso nella comunità dei nodes sembra essere che Cluster sia ora il modulo preferito per la gestione di più istanze di nodes per macchina. Per sempre vale anche la pena dare un’occhiata.

Multi-node sfrutta tutti i core che potresti avere.
Dai un’occhiata a http://github.com/kriszyp/multi-node .

Per esigenze più semplici, è ansible avviare più copie del nodo su diversi numeri di porta e posizionare un servizio di bilanciamento del carico di fronte a tali numeri.

È ansible utilizzare il modulo cluster . Controlla questo .

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

Come accennato in precedenza, Cluster ridimensiona e bilancia il carico della tua app su tutti i core.

aggiungendo qualcosa di simile

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

Riavvierà eventuali lavoratori in errore

Oggigiorno, molte persone preferiscono anche PM2 , che gestisce il clustering per te e fornisce anche alcune interessanti funzionalità di monitoraggio .

Quindi, aggiungere Nginx o HAProxy davanti a diversi computer in esecuzione con il clustering e disporre di più livelli di failover e una capacità di carico molto più elevata.

La versione futura del nodo consentirà di eseguire il fork di un processo e di passare messaggi ad esso e Ryan ha dichiarato che vuole trovare un modo per condividere anche i gestori di file, quindi non sarà un’implementazione Web Worker semplice.

In questo momento non c’è una soluzione facile per questo, ma è ancora molto presto e node è uno dei progetti open source in più rapida evoluzione che abbia mai visto, quindi aspettatevi qualcosa di fantastico nel prossimo futuro.

Spark2 è basato su Spark che ora non è più mantenuto. Il cluster è il suo successore e presenta alcune funzioni interessanti, come la generazione di un processo di lavoro per core della CPU e il risanamento dei lavoratori morti.

Il nodo Js supporta il clustering per sfruttare tutti i vantaggi della CPU. Se non lo stai eseguendo con il cluster, probabilmente stai sprecando le tue capacità hardware.

Il cluster in Node.js consente di creare processi separati che possono condividere la stessa porta server. Ad esempio, se eseguiamo un server HTTP su Port 3000, è un server in esecuzione su thread singolo su un singolo core del processore.

Il codice mostrato di seguito consente di raggruppare l’applicazione. Questo codice è codice ufficiale rappresentato da 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. } 

controlla questo articolo per il tutorial completo

Sto usando il lavoratore Node per eseguire i processi in un modo semplice dal mio processo principale. Sembra funzionare alla grande mentre aspettiamo il modo ufficiale di venire in giro.

Il nuovo bambino sul blocco qui è “Up” di LearnBoost.

Fornisce “ricariche Zero-downtime” e crea inoltre più worker (di default il numero di CPU, ma è configurabile) per fornire il meglio di tutti i Worlds.

È nuovo, ma sembra essere abbastanza stabile, e lo sto usando felicemente in uno dei miei progetti attuali.

Il modulo cluster ti consente di utilizzare tutti i core della tua macchina. In effetti puoi approfittare di questo in soli 2 comandi e senza toccare il tuo codice usando un gestore di processi molto popolare pm2 .

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

È anche ansible progettare il servizio web come diversi server stand alone che ascoltano i socket unix, in modo da poter spingere funzioni come l’elaborazione dei dati in processi separati.

Questo è simile alla maggior parte delle architetture web server di scruping / database in cui un processo cgi gestisce la logica di business e quindi spinge e trascina i dati tramite un socket unix in un database.

la differenza è che l’elaborazione dei dati viene scritta come un server web nodo in ascolto su una porta.

è più complesso, ma alla fine è il suo sviluppo multi-core. un’architettura multiprocesso che utilizza più componenti per ogni richiesta web.

È ansible ridimensionare NodeJS su più box utilizzando un puro bilanciatore del carico TCP (HAProxy) davanti a più box che eseguono un processo NodeJS ciascuno.

Se si dispone quindi di conoscenze comuni da condividere tra tutte le istanze, è ansible utilizzare un negozio Redis centrale o simile che può quindi essere accessibile da tutte le istanze del processo (ad esempio da tutte le caselle)