> Как писать приложение для корректной работы в кластерном режиме с несколькими воркерами (JavaScript)

Уровень: senior · Роль: backend · Язык: JavaScript · Категория: Технические вопросы

Компании: QueenInteractiveGamesLtd

Стек: Node.js, JavaScript

> Пример ответа

Для корректной работы Node.js приложения в кластерном режиме с несколькими воркерами необходимо учитывать несколько ключевых аспектов. Во-первых, используйте встроенный модуль cluster, который позволяет создавать дочерние процессы (воркеры), разделяющие один и тот же порт. Главный процесс (master) управляет воркерами, а каждый воркер обрабатывает запросы независимо.

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

JAVASCRIPT
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} запущен`);
// Создаем воркеры по числу ядер CPU
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
// Перезапуск упавших воркеров
cluster.on('exit', (worker, code, signal) => {
console.log(`Воркер ${worker.process.pid} умер`);
cluster.fork();
});
} else {
// Воркеры: создаем HTTP сервер
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello from worker ' + process.pid);
}).listen(8000);
console.log(`Воркер ${process.pid} запущен`);
}

Ключевые моменты для корректной работы:

  1. Общее состояние: Избегайте хранения состояния в памяти воркера (например, сессии, кэш). Используйте внешние хранилища (Redis, база данных) для синхронизации между воркерами.

  2. Грейсфул шатдаун: Обрабатывайте сигналы завершения (SIGTERM, SIGINT) для корректного закрытия соединений и освобождения ресурсов:

    JAVASCRIPT
    process.on('SIGTERM', () => {
    server.close(() => process.exit(0));
    });
  3. Балансировка нагрузки: Node.js автоматически распределяет входящие соединения между воркерами через round-robin (на Linux) или через сокеты (на Windows). Для более тонкой настройки используйте сторонние балансировщики (NGINX).

  4. Логирование и мониторинг: Добавьте идентификатор воркера в логи (через process.pid или cluster.worker.id), чтобы отслеживать, какой воркер обрабатывает запрос.

  5. Избегайте блокирующих операций: Воркеры должны быть неблокирующими. Если есть тяжелые вычисления, выносите их в отдельные процессы или используйте worker_threads.

  6. Обработка ошибок: Воркеры могут падать, поэтому мастер должен перезапускать их (как в примере выше). Также используйте process.on('uncaughtException') для логирования, но не пытайтесь восстановить работу воркера - лучше дать ему умереть и перезапустить.

Этот подход обеспечивает отказоустойчивость, масштабирование и корректную работу приложения в многопроцессной среде.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью