ویژگی تصویر

مدیریت فرایندها با Cluster در Node.js

  /  Node.js   /  مدیریت فرایندها با Cluster در Node.js
بنر تبلیغاتی الف
NodeJS - Node.js

ماژول Cluster در Node.js ابزاری است برای اجرای چندین فرایند (process) همزمان از یک برنامهٔ سرور، به‌منظور استفادهٔ بهینه از هسته‌های CPU و افزایش ظرفیت پاسخ‌گویی. هر Worker یک فرآیند مجزا دارد و حلقهٔ رویداد (event loop) و حافظهٔ خود را دارا است، بنابراین محدودیت تک‌نخی بودن Node.js با توزیع بار میان چند فرایند کاهش می‌یابد.

چرا از Cluster استفاده کنیم؟

  • استفادهٔ کامل از چند هستهٔ CPU
  • افزایش تحمل خطا (اگر یک Worker کرش کند، دیگران به کار ادامه می‌دهند)
  • قابلیت کار با ترافیک بالا و کاهش زمان پاسخ
  • قابلیت مدیریت چرخهٔ عمر Workerها (restart، graceful shutdown و غیره)

مفاهیم کلیدی

  • Master/Primary: فرایندی که کنترل fork و مدیریت Workerها را برعهده دارد.
  • Worker: فرایندهای فرعی که اپلیکیشن را اجرا می‌کنند و درخواست‌ها را پاسخ می‌دهند.
  • IPC: ارتباط بین فرایندی که با پیام‌ها (worker.send / process.on(‘message’)) انجام می‌شود.
  • Scheduling Policy: شیوهٔ توزیع اتصالات بین Workerها (SCHED_RR یا SCHED_NONE).

نمونهٔ ساده: راه‌اندازی HTTP Server با Cluster

const cluster = require('cluster');
const http = require('http');
const os = require('os');

if (cluster.isMaster) {
  const cpus = os.cpus().length;
  console.log(`Master ${process.pid} is running. Forking ${cpus} workers...`);
  for (let i = 0; i  {
    console.log(`Worker ${worker.process.pid} died. Forking a new one.`);
    cluster.fork();
  });
} else {
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Handled by worker ${process.pid}`);
  }).listen(3000);
  console.log(`Worker ${process.pid} started`);
}

این کد تعداد Workerها را برابر با تعداد هسته‌های CPU سیستم می‌کند و برای هر یک یک سرور HTTP اجرا می‌کند. در صورت کرش کردن یک Worker، Master یک Worker جدید می‌سازد. هر Worker یک فرآیند مجزا است و درخواست‌ها را پردازش می‌کند.

نکات فنی و بهینه‌سازی‌ها

  • پیش‌فرض زمان‌بندی در بعضی پلتفرم‌ها SCHED_RR (round-robin) است — می‌توانید آن را با cluster.schedulingPolicy تنظیم کنید.
  • دقت کنید که حافظهٔ اشتراکی وجود ندارد؛ برای اشتراک داده باید از دیتابیس یا حافظهٔ مشترک مانند Redis استفاده کنید.
  • نباید Workerها را بیش از حد از تعداد هسته‌ها افزایش دهید؛ این باعث contention و overhead بیشتر می‌شود.

ارتباط بین Master و Worker

// master.js
const cluster = require('cluster');
if (cluster.isMaster) {
  const worker = cluster.fork();
  worker.on('message', msg => {
    console.log('Message from worker:', msg);
  });
  worker.send({ cmd: 'status' });
} else {
  process.on('message', msg => {
    if (msg.cmd === 'status') {
      process.send({ pid: process.pid, uptime: process.uptime() });
    }
  });
}

در این مثال Master به یک Worker پیام می‌فرستد و Worker با استفاده از process.send به Master پاسخ می‌دهد. این مکانیزم برای اطلاع‌رسانی، تغییر تنظیمات یا هماهنگی بین فرایندها مناسب است.

Graceful Restart و Shutdown

راه‌اندازی مجدد بی‌وقفه (zero-downtime) یا خاموشی کنترل‌شده برای جلوگیری از قطع سرویس ضروری است. ایدهٔ کلی: ابتدا یک Worker جدید را بسازید، سپس Worker قدیمی را به‌تدریج از کار بیندازید و اجازه دهید درخواست‌های جاری تکمیل شوند.

const cluster = require('cluster');
const http = require('http');
const os = require('os');

if (cluster.isMaster) {
  const cpus = os.cpus().length;
  for (let i = 0; i  { // مثال: سیگنال برای ری‌استارت
    const workers = Object.values(cluster.workers);
    const restartWorker = (i) => {
      if (i >= workers.length) return;
      const worker = workers[i];
      worker.disconnect();
      const timeout = setTimeout(() => worker.kill(), 5000);
      worker.on('exit', () => {
        clearTimeout(timeout);
        const newWorker = cluster.fork();
        newWorker.on('listening', () => restartWorker(i + 1));
      });
    };
    restartWorker(0);
  });
} else {
  const server = http.createServer((req, res) => {
    res.end(`Handled by ${process.pid}`);
  }).listen(3000);

  // اجازه به تکمیل درخواست‌ها هنگام disconnect
  process.on('disconnect', () => {
    server.close(() => process.exit(0));
    setTimeout(() => process.exit(1), 10000);
  });
}

در این کد، Master به‌نحوی از هر Worker جدا می‌شود که ابتدا Worker جدید بالا بیاید و پس از آن Worker قدیمی به آرامی متوقف شود. استفاده از server.close باعث می‌شود که Worker درخواست‌های جاری را کامل کند و از پذیرش درخواست جدید خودداری کند.

Sticky Sessions و وضعیت کاربر

اگر اپلیکیشن شما مبتنی بر نشست‌ها (sessions) است و می‌خواهید اتصال کاربر همواره به یک Worker مشخص برود (مثلاً برای WebSocket یا session ذخیره‌شده در حافظهٔ فرایند)، باید از مکانیزم sticky sessions استفاده کنید. دو راه اصلی:

  • استفاده از Load Balancer بیرونی (Nginx، HAProxy) که sticky session را مدیریت می‌کند.
  • پیاده‌سازی sticky routing در سطح Node با استفاده از net.createServer و hash آی‌پی یا cookie.

معمولاً بهتر است وضعیت نشست در یک فروشگاه متمرکز (Redis) ذخیره شود تا نیازی به sticky session نباشد.

مقایسه کوتاه: Cluster vs worker_threads vs Process Manager

فناوریمناسب برایمزایامعایب
Clusterافزایش Throughput و استفاده از CPUساده، سازگار با کدهای موجودفرایندهای جدا؛ حافظه اشتراکی ندارد
worker_threadsمحاسبات CPU-bound با نیاز به اشتراک حافظهاشتراک ArrayBuffer و پیام‌دهی سریعپیچیدگی همگام‌سازی، مناسب برای بخش‌های محاسباتی
Process Manager (PM2)Deploy و مدیریت پروسه‌ها در تولیدقابلیت cluster، load balancing، مانیتورینگابزار اضافه برای مدیریت

نکات عملی و توصیه‌های متخصصی

  • در محیط تولید از Process Managerهایی مانند PM2 یا systemd استفاده کنید تا مدیریت crash و رول‌بک آسان‌تر باشد.
  • برای وضعیت‌های مشترک از Redis یا دیتابیس استفاده کنید؛ فرض نگه‌داشتن session در حافظهٔ Worker خطرناک است.
  • قبل از fork کردن، منابعی که باز هستند (Socket، DB connection) را مدیریت کنید؛ بعضی منابع نیاز به recreate در Worker دارند.
  • برای تست بار واقعی از ابزارهایی مانند wrk یا k6 استفاده کنید تا تعداد مناسب Worker را تعیین کنید.

جمع‌بندی

ماژول Cluster راهی استاندارد و قدرتمند برای مدیریت فرایندها در Node.js است که با استفادهٔ درست می‌تواند بهره‌وری CPU و پایداری سرویس‌ها را به‌طور قابل‌توجهی افزایش دهد. با این حال در کنار مزایا باید به چالش‌های همگام‌سازی و مدیریت وضعیت توجه شود؛ استفاده از ابزارهایی مانند Redis، PM2 و ساختار graceful restart به ایجاد سرویس‌های مقیاس‌پذیر و قابل‌اطمینان کمک می‌کند.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: