Что такое cluster в Node.js?

Ответ

Cluster — это встроенный модуль Node.js, который позволяет создавать несколько дочерних процессов (воркеров) для параллельного выполнения кода на многоядерных процессорах. Поскольку Node.js работает в одном потоке, кластеризация — это основной способ горизонтального масштабирования приложения на уровне ОС.

Как это работает:

  • Главный процесс (master) создаёт несколько воркеров с помощью cluster.fork().
  • Все воркеры выполняют один и тот же исходный код сервера.
  • Входящие соединения распределяются между воркерами (по умолчанию — алгоритм round-robin).
  • Воркеры используют общий серверный порт через механизм IPC (Inter-Process Communication).

Пример базовой реализации:

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isPrimary) {
  console.log(`Primary process ${process.pid} is running`);

  // Создаём воркеров по количеству ядер CPU
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died. Restarting...`);
    cluster.fork(); // Автоматический перезапуск упавшего воркера
  });
} else {
  // Код, выполняемый воркерами
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Response from worker ${process.pid}`);
  }).listen(3000);

  console.log(`Worker ${process.pid} started`);
}

Практическое применение: Кластеризация критически важна для веб-серверов (например, на Express.js или Fastify), чтобы полностью использовать ресурсы сервера и повысить отказоустойчивость. В продакшене часто используется в связке с менеджером процессов PM2, который предоставляет более удобный интерфейс для кластеризации.

Ответ 18+ 🔞

Э, слушай, а давай про эту вашу кластеризацию в Node.js поговорим. Вещь, в общем-то, архиполезная, а многие её как мантру повторяют, не особо вникая, что там под капотом. Ну, типа, «надо форкаться, ядра использовать». А почему? А потому что Node.js, он, сука, однопоточный, как этот твой знакомый, который в доту режется и на звонки не отвечает. Всё в одном потоке крутится. И если у тебя сервак на 16 ядер, а приложение в одном ядре сидит — это же пиздец, товарищ. Остальные 15 ядер просто курят в сторонке, пока одно ядро ебётся с нагрузкой. Волнение ебать просто от такой несправедливости.

Так вот, модуль cluster — это как раз способ сказать системе: «Эй, ядра, ёпта, не проёбывайтесь!». Главный процесс, он же мастер, запускается. Его задача — наделать кучу детей-воркеров. Каждый воркер — это отдельный процесс Node.js, который тупо выполняет ТОТ ЖЕ САМЫЙ код твоего сервера. И все они, ебушки-воробушки, начинают слушать один и тот же порт. Как так выходит? А это магия IPC (Inter-Process Communication), проще говоря, они между собой договариваются, кто из них какой запрос обработает.

Самый простой пример, чтоб въехать, выглядит как-то так:

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isPrimary) {
  console.log(`Primary process ${process.pid} is running`);

  // Создаём воркеров по количеству ядер CPU
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died. Restarting...`);
    cluster.fork(); // Автоматический перезапуск упавшего воркера
  });
} else {
  // Код, выполняемый воркерами
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Response from worker ${process.pid}`);
  }).listen(3000);

  console.log(`Worker ${process.pid} started`);
}

Смотри, что тут происходит. Мастер (cluster.isPrimary) — он плодовитый такой, хуй с горы. Берёт количество ядер на твоей машине и на каждое ядро создаёт по воркеру (cluster.fork()). А дальше он просто сидит и ждёт. Если какой-то воркер, не дай бог, накрылся медным тазом и умер, мастер это видит (cluster.on('exit')) и тут же запускает нового. Отказоустойчивость, мать её.

А воркеры — они уже тупо запускают сервер. Весь код после else — это их жизнь. Они все стартуют HTTP-сервер на порту 3000. И когда приходит запрос, операционка (или сам Node, смотря какая версия) по умолчанию раскидывает их по кругу (round-robin) между всеми воркерами. Один запрос — первому воркеру, второй — второму, и так по кругу. Распределение нагрузки, ёпта!

На практике это овердохуища важно для любого нормального веб-сервера на Express, Fastify или на чём ты там любишь. Без кластеризации ты используешь мощности своего сервера на 5-10%, а остальное — просто греет воздух. Это как купить Ferrari и кататься на ней только на первой передаче до магазина за хлебом. Удивление пиздец.

Правда, в реальной жизни народ редко пишет эту логику руками. Чаще используют PM2 — это такой менеджер процессов, который из коробки умеет и кластеризовать, и логи писать, и при падении перезапускать. Он под капотом делает всё то же самое, но тебе не нужно париться с этим кодом. Но понимать, как это работает — обязательно. А то будешь как полупидор, который PM2 запустил, а на вопрос «как это работает» — глаза в потолок. Не комильфо.