
Node.js deve buona parte del suo successo all’efficienza che lo contraddistingue: consuma poche risorse e lavora su un unico thread permettendo comunque attività asincrone. Questi ed altri vantaggi l’hanno reso molto utile per creare servizi di piccole dimensioni in grado di modularizzare il lavoro: approccio ideale in un’epoca che vede il successo delle architetture basate su Microservizi.
Il modulo di cui parliamo oggi si chiama cluster e permette di parallelizzare il lavoro creando un processo server in grado di generare suoi propri figli tramite il metodo fork.
Ribadiamo che stiamo trattando di creazione di processi multipli, quindi non multi-threading in uno stesso processo, pertanto i worker, ossia i processi figlio, potranno comunicare tra loro utilizzando le tecniche di IPC (InterProcess Communication).
Vediamo come funziona questo modulo:
- scriveremo una porzione di codice che dovrà essere svolta dal processo iniziale, detto master, nella quale essenzialmente andremo ad effettuare le fork per creare i processi figlio;
- nella porzione di script relativo ai processi figlio eseguiremo il codice che vorremo parallelizzare. Si noti a questo punto che, in un cluster, tipicamente tutti i processi figlio svolgono lo stesso tipo di attività.
Molto interessante è anche considerare che se nel codice dei processi worker attiveremo un servizio – ad esempio, API REST con Express – tutti i processi figlio rimarranno in ascolto sulla stessa porta creando effettivamente un cluster in grado di bilanciare il carico di risposta di un medesimo servizio.
Nell’esempio seguente, creiamo un servizio REST, con tanti processi figlio quanti ne permette il processore (tramite il modulo os verifichiamo il numero di CPU disponibili) ed ogni figlio eseguirà le API Express sulla stessa porta TCP, in questo caso la 4200:
var cluster = require('cluster'); if(cluster.isMaster) { // codice processo master: facciamo partire i processi worker var numCPU = require('os').cpus().length; // eseguiamo tante fork quanti sono le CPU disponibili for(var i = 0; i < numCPU; i++) { cluster.fork(); } } else { // codice del processo worker var app = require('express')(); app.get('/', function (req, res) { res.send('Risposta dal processo ' + process.pid); }); var server = app.listen(4200, function() { console.log('Avviato processo con PID ' + process.pid); }); }
All’interno del codice dei worker (nel blocco else, in pratica) abbiamo disponibile anche la variabile process tramite la quale potremo leggere il PID, l’identificativo univoco che distingue il processo nel sistema operativo.
Sull’oggetto cluster potremo anche reagire ad una serie di eventi relativi ai processi worker come online che ne segnala l’entrata in funzione ed exit che ne notifica la conclusione del lavoro. La sintassi di impiego sarà la seguente:
var cluster = require('cluster'); ... ... cluster.on('online', function(worker) { /* worker (un processo figlio) entrato in esecuzione tramite worker.process ne possiamo leggere le proprietà */ });
Ecco un altro esempio di come Node.js sia in grado fornire un servizio utile con poche righe di codice. Efficienza, flessibilità e semplicità: queste le sue parole d’ordine.
Che ne pensate? Fateci sapere!
No Responses to “Node.js: parallelizzare il lavoro con il modulo cluster”