Clusters
El modulo cluster permite la creación de procesos hijos que comparten un mismo puerto, es muy usado cuando estamos creando un servidor (http o net) para crear un balanceador de carga es decir vamos a tener varias instacias de nuestro servidor y cuando una este muy ocupada se va a usar otra instacia (el procesos padre se encarga de distribuir la carga generalmente por medio del método de planificación round-robin).
Es recomendable solo crear unos pocos procesos para que así nuestra aplicación se comporte de manera adecuada, una técnica muy común es solo crear procesos como núcleos tenga nuestro ordenador, aunque podemos crear muchos más con esto solo lograríamos que nuestro sistema operativo tenga que hacer más trabajo para encolar y programar estos procesos.
Worker
Cada vez que creamos un nuevo proceso a este se le llama worker y se genera con child_process.fork()
el cual nos permite tener una comunicación bidireccional. En el siguiente ejemplo podemos comparar el uso de child_process.fork()
y cluster
, cuando usamos fork tenemos un archivo para el padre y uno para el hijo, con cluster solo debemos tener un archivo donde el if el el padre y el else es el hijo.
const cluster = require('cluster');
if (cluster.isMaster) {
// Parent
const worker = cluster.fork();
worker.send('hi there');
worker.on('message', (msg) => {
console.log(`Worker said: ${msg}`);
});
} else if (cluster.isWorker) {
// Child
process.on('message', (msg) => {
console.log(`Master said ${msg}`);
process.send(msg);
});
}
const express = require('express');
const cluster = require('cluster');
const totalCpus = require('os').cpus().length;
function fib(n) {
if (n > 1) {
return fib(n - 1) + fib(n - 2)
} else {
return n;
}
}
if (cluster.isMaster) {
for (let i = 0; i < totalCpus; i++) {
// Create a new worker in this case a http server
cluster.fork();
}
for (const id in cluster.workers) {
cluster.workers[id].on('message', (msg) => {
console.log(`Worker-${id} said: ${msg} to Master`);
});
cluster.workers[id].on('listening', (address) => {
cluster.workers[id].send("Welcome")
});
}
cluster.on('online', (worker) => {
console.log(
`Worker Id is ${worker.id} and the PID is: ${worker.process.pid}`
);
});
cluster.on('exit', (worker) => {
console.log(
`Worker Id ${worker.id} with PID ${worker.process.pid} is offline`
);
});
cluster.on('error', (error) => {
console.log(error);
});
} else {
const app = express();
app.get('/', (req, res) => {
let number = fib(
Number.parseInt(req.query.number)
);
process.send(number);
res.send(`<h1>${number}</h1>`);
});
app.get('/message', (req, res) => {
const data = req.query.data;
process.send(data);
res.send(data);
});
process.on('message', (msg) => {
console.log(`Master said ${msg} to worker`);
});
app.listen(3000, () => console.log('Express server is running on port 3000'));
}