Node.js Cluster 模組:利用多核心 CPU 實現水平擴展

預設情況下,Node.js 程式運行在單一個 CPU 核心上。如果你的伺服器擁有 8 核心甚至更多,那麼其餘的核心將會處於閒置狀態。Cluster (叢集) 模組允許你輕鬆啟動多個子進程,將連線酬載均勻分配到所有核心,達成真正的水平擴展。

運作原理:Primary 與 Workers

在 Node.js 16+ 之後,官方推薦使用 Primary 替代舊稱的 Master。

  • Primary (主進程):負責管理、監控與分配任務,本身不處理具體的網路請求。
  • Workers (工作進程):真正的執行者。多個 Worker 共享同一個 TCP 連線埠 (Port),由 Primary 以 Round-Robin (輪詢) 演算法自動分配傳入的請求。

基礎實戰範例

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

if (cluster.isPrimary) {
  console.log(`主進程 ${process.pid} 正在啟動,預計分配給 ${numCPUs} 個核心...`);

  // 根據核心數產生對應的工作者
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  // 監聽結束事件:當某個 Worker 崩潰時自動重啟
  cluster.on('exit', (worker, code, signal) => {
    console.warn(`工作進程 ${worker.process.pid} 已離線,正在自動遞補...`);
    cluster.fork();
  });
} else {
  // 每個工作進程都會獨立跑一個 HTTP Server
  http
    .createServer((req, res) => {
      res.writeHead(200);
      res.end(`由進程 ID: ${process.pid} 為您服務`);
    })
    .listen(8080);

  console.log(`工作進程 ${process.pid} 已就緒`);
}

為什麼要使用 Cluster?

  1. 效能翻倍:隨著核心數增加,伺服器的總吞吐量會呈線性成長。
  2. 高可用性 (High Availability):如果其中一個工作進程因為程式 Bug 崩潰,主進程可以立即拉起一個新的補充,整個系統幾乎可以做到 零停機 (Zero Downtime)

核心限制:記憶體隔離

由於每個 Worker 都是獨立的作業系統進程,因此它們 不能共享全域變數

  • 錯誤做法:在 JavaScript 全域變數裡計算「連線總數」,每個 Worker 都只會讀到自己的局部數字。
  • 正確做法:將需要共享的狀態存放在外部的 Redis 或資料庫中。

專業部署建議:PM2

雖然 cluster 模組很好用,但在實際的生產環境中,Node.js 開發者通常會選擇使用 PM2

PM2 是一個內建了 Cluster 模式的進程管理器,它提供了更強大的日誌管理、自動監控排程以及優雅重啟 (Graceful Reload) 功能。

總結

  1. cluster 是解決 Node.js 單核限制的內建方案。
  2. 它適合處理大量的網路連線 (I/O 密集型)。
  3. 在生產環境中,推薦了解 cluster 原理後改用 PM2 進行自動化管理。