O módulo cluster do Node.js possibilita criar múltiplos processos filhos (workers) que compartilham uma mesma porta de servidor. Essa abordagem permite explorar ao máximo CPUs com vários núcleos, melhorando o desempenho e a resiliência da aplicação.
Como Funciona Internamente
Baseado no child_process, o módulo cluster opera com um processo principle (master) e processos trabalhadores (workers):
- Processo principle (master): Responsável por gerenciar e distribuir tarefas para os workers.
- Processos trabalhadores (workers): Executam o código do servidor e processam as requisições.
Existem duas formas de lidar com as conexões no cluster:
- Roteamento via master: O master escuta a porta, recebe a requisição HTTP e a encaminha via IPC para um worker. O worker processa e devolve o resultado ao master, que o retorna ao cliente.
- Conexão direta: O master apenas notifica o worker, que estabelece uma conexão direta com o cliente.
Embora a segunda pareça mais eficiente, na prática o roteamento via master costuma oferecer melhor balanceamento de carga devido a limitações de escalonamento do sistema operacional. (ref)
Passos Básicos para Usar o Cluster
- Verificar se o processo atual é o principal usando
cluster.isPrimary(oucluster.isMaster). - No processo principal, criar workers com
cluster.fork(). - Nos workers, executar o código do servidor (ex: HTTP).
Exemplo prático:
const cluster = require("node:cluster");
const http = require("node:http");
const totalCpus = require("node:os").cpus().length;
if (cluster.isPrimary) {
console.log(`Processo principal PID: ${process.pid} em execução`);
// Cria um worker para cada núcleo da CPU
for (let i = 0; i < totalCpus; i++) {
cluster.fork();
}
cluster.on("exit", (worker, code, signal) => {
console.log(`Worker com PID ${worker.process.pid} foi encerrado`);
});
} else {
// Código executado pelos workers
http.createServer((req, res) => {
let pid = process.pid;
res.writeHead(200, { "Content-Type": "text/plain" });
res.end(`Resposta do worker ${pid}\n`);
}).listen(8000);
console.log(`Worker PID ${process.pid} iniciado`);
}
Vantagens do Uso de Cluster
- Melhor desempenho: Aproveita múltiplos núcleos do processador para aumentar a capacidade de atender requisições simultâneas.
- Alta disponibilidade: Se um worker falhar, os demais continuam operando e o master pode recriá-lo.
- Balanceamento automático: Os workers compartilham a mesma porta, distribuindo as requisições de forma transparente.
Pergunta para Reflexão
Considere um servidor HTTP que escuta na porta 8000. Com o cluster, é possível rodar múltiplos workers escutando na mesma porta. Porém, se você executar o código abaixo duas vezes em processos independentes, o segundo lançará um erro "porta já em uso". Por que isso acontece?
// servidor.js
const http = require("node:http");
http.createServer((req, res) => {
let pid = process.pid;
res.writeHead(200);
res.end(`Worker PID: ${pid}\n`);
}).listen(8000);
Deixe sua opinião nos comentários. Se o post atingir 20 curtidas, publicarei a explicação detahlada.