首頁  >  文章  >  web前端  >  叢集和工作線程 - Node JS

叢集和工作線程 - Node JS

Patricia Arquette
Patricia Arquette原創
2024-11-26 00:22:11435瀏覽

Clustering and Worker Threads - Node JS

在上一篇文章「Node JS 內部結構」中,我們討論了Node JS 內部架構,並討論了為什麼我們應該增加節點線程池大小以同時處理多個請求。我已經告訴過你,可擴展性和效能與線程池大小無關。

為了可擴展性和高效能,我們可以使用叢集和工作執行緒。

聚類

假設您正在參加一場盛大的婚禮,有數千位賓客參加婚禮。有一間廚房,一名廚師正在為所有這些客人準備食物。聽起來不可預測,對吧?如果您只有一名廚師,您就沒有充分利用廚房的全部資源。

這正是在多核心 CPU 上執行的 Node JS 應用程式中發生的情況,當僅使用一個核心來處理所有請求時。因此,即使我們的機器具有多核心的能力,如果沒有集群,我們的應用程式也只能在單核心上運行。一個核心負責處理所有工作。

當你的廚房裡有多個廚師正在工作時,這就是集群。

叢集是一種讓單一 Node JS 應用程式能夠有效利用多個 CPU 核心的技術。

要實作集群,您必須使用 Node JS 中的集群模組。

const cluster = require('cluster');

透過使用此叢集模組,您可以建立 Node JS 應用程式的多個實例。這些實例稱為工人。所有工作人員共用相同的伺服器連接埠並同時處理傳入請求。

叢集架構中有兩種類型的進程。

1.主流程:

Master進程就像廚房裡的主廚管理工人。它初始化應用程序,設定叢集環境,並將任務委託給工作進程。它不直接處理應用程式請求。

Master進程是做什麼的?

  • 使用 cluster.fork() 方法建立多個工作進程。如果工作人員意外崩潰或退出,它也會重新啟動工作人員。

  • 它確保傳入請求分佈在所有工作流程中。在 Linux 上,這是由作業系統處理的,在 Windows 上,Node JS 本身充當負載平衡器。

  • 它可以透過IPC(進程間通訊)在worker之間進行通訊。

2.工作進程:

工作進程是主進程所建立的 Node JS 應用程式的實例。每個進程在單獨的 CPU 核心上獨立運行並處理傳入請求。

工作進程無法直接相互通信,它們透過主進程進行通訊。

工作進程處理傳入的請求並執行一些任務,例如資料庫查詢、計算或任何應用程式邏輯。

const cluster = require('cluster');

在這裡,我們先檢查這是主進程。如果是,那麼它將創建工作進程。

在我們的程式碼中,我使用 cluster.fork() 建立一個工作進程。

但是,這不是創建工作進程的理想方式。

假設您正在建立 4 個工作進程,而您的系統有兩個核心。

為了解決這個問題,而不是創建硬編碼的工作進程,先找到 CPU 核心,然後考慮資料創建工作進程。

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

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

  // Fork workers
    cluster.fork();
    cluster.fork();
    cluster.fork();
    cluster.fork();

} else {
  console.log(`Worker ${process.pid} is running`);
  // Worker logic (e.g., server setup) goes here
}

我使用雙核心系統,所以輸出將如下所示。

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

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);
  const numCPUs = os.cpus().length;

  // Fork workers
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  console.log(`Worker ${process.pid} is running`);
  // Worker logic (e.g., server setup) goes here
}

現在,您有一個問題,如果您有雙核心 CPU,那麼為什麼要建立 4 個工作進程?

這是因為邏輯核心數為 4,我的 CPU 支援超執行緒或同步多執行緒 (SMT)。

工作執行緒

在餐廳裡,服務生接受訂單並將訂單交給廚師團隊,因為烹飪需要一些時間。如果有清潔桌子或任何其他與服務員相關的工作,那麼服務員就會這樣做。當訂單準備好後,廚師將食物回饋給服務員,服務員將這些食物提供給顧客。

這與工作執行緒相關的場景相同。如果出現任何計算量大的任務,例如大規模資料處理、複雜計算或繁重演算法,則主執行緒會將此任務委託給工作執行緒。該任務由工作執行緒執行,而不是主執行緒。

*為什麼,這有幫助? *

我們知道 Node JS 事件循環是單執行緒的,如果這種繁重的運算工作由主執行緒完成,那麼事件循環將被阻塞。如果您使用這些工作線程,那麼這些繁重的任務將交給工作線程,工作線程執行這些任務,而不是主線程,因此事件循環不會被阻塞。

工作執行緒可以透過訊息傳遞系統與主執行緒通信,並且可以使用結構化克隆(深複製)在執行緒之間發送資料。

現在,我們正在嘗試模仿工作執行緒的工作。

main.js(主執行緒)

Master 12345 is running
Worker 12346 is running
Worker 12347 is running
Worker 12348 is running
Worker 12349 is running

worker.js(工作執行緒)

const { Worker } = require('worker_threads');

function startWorker() {
  const worker = new Worker('./worker.js'); // Create a worker using worker.js

  // Listen for messages from the worker
  worker.on('message', (message) => {
    console.log('Message from worker:', message);
  });

  // Handle errors in the worker
  worker.on('error', (error) => {
    console.error('Worker error:', error);
  });

  // Handle worker exit
  worker.on('exit', (code) => {
    console.log(`Worker exited with code ${code}`);
  });

  // Send a message to the worker
  worker.postMessage({ num: 100 });
}

startWorker();

如果資料包含大型結構,它將被深度克隆並傳遞,這可能會產生一些效能開銷。

程式碼的工作

  • Worker 類別用於產生新執行緒。

  • 您可以使用worker.postMessage向worker發送數據,並使用worker.on('message',callback)監聽訊息。

  • 在工作執行緒中,parentPort 是與主執行緒通訊的主要介面。

  • 您可以監聽來自主執行緒(parentPort.on('message'))的訊息並使用parentPort.postMessage傳回訊息。

輸出將是:

const cluster = require('cluster');

現在,您還有一個問題:為什麼我們不建立數百個工作執行緒?

但是,原因是如果您建立的執行緒多於核心數量,執行緒將競爭 CPU 時間,導致上下文切換,這會導致成本高昂並降低整體效能。

什麼時候應該在 Node.js 中使用叢集、工作執行緒或兩者?

1。何時使用工作執行緒?

  • CPU 密集任務:

涉及大量計算的任務,例如影像/視訊處理、資料壓縮或加密、機器學習推理、科學計算

  • 需要共享記憶體:

您需要在執行緒之間有效地共享資料而不重複資料。

  • 單核心使用:

如果您的應用程式只需要在單一進程內擴展,但仍需要 CPU 密集型任務的並行性。

2.什麼時候使用聚類?

  • I/O 限制:

任務涉及處理大量客戶端請求,例如 Web、伺服器、聊天應用程式和 API。叢集透過在所有 CPU 核心之間分配請求來幫助水平擴展。

  • 孤立的記憶:

您的應用程式不需要在進程之間共享大量資料。

  • 多核心利用率:

您希望透過產生多個 Node.js 進程來利用所有可用的核心。

3.什麼時候同時使用叢集和工作執行緒?

  • I/O 密集型 CPU 密集型任務:

應用程式處理 HTTP 請求,但卸載計算密集型任務。範例:網頁伺服器處理檔案上傳並執行影像大小調整或影片轉碼。

  • 高擴充性:

您需要進程級和執行緒級並行性才能實現高吞吐量。在電子商務網站中,叢集可確保多個進程處理傳入要求。工作執行緒處理後台任務,例如產生個人化推薦。

謝謝。

歡迎提出問題或提出任何建議。

如果您發現本文內容豐富,請按讚。

以上是叢集和工作線程 - Node JS的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn