Skip to main content

Command Palette

Search for a command to run...

透過 Nodejs cluster module 處理併發的 CPU intensive job

Updated
2 min read

簡介

本文將會簡介如何透過 nodejs cluster module 來解決併發的 CPU intensive job 所造成系統阻塞問題

問題描述

一個 Nodejs 所啟動的服務會使用單一執行緒來執行所有任務

透過 libuv 的 Event loop 實踐 Non Blocking I/O

當有多個併發 CPU Intensive Job 將會讓 Nodejs Server 卡住其他 Requests

Nodejs cluster 架構

這時就可以透過 cluster 概念來啟用其他 CPU 的 Core 來做運算

如下圖

紅色的部份這些並行的 Nodejs 執行個體個別使用不同的 CPU core

因此不會卡住彼此的 Request

而這些紅色的 NodeJs 執行個體可以組成一個大的運算單位來當作服務,這概念可以稱作 叢集(Cluster)

通常會使用一個主要的 Nodejs 執行個體當作 api gateway 負責分派任務給 cluster 內所有可用得執行個體來處理 Request

範例

以下將會以 Nodejs 範例,示範如何使用 cluster mode 來做均衡 workload

主要分為

  1. 使用 cluster module 處理

  2. 使用 pm2 來達成這件事情

  3. 分別使用 loadtest 來做 benchmark 測試驗證

1. 使用工具

  1. loadtest: 做 benchmark 的 nodejs module

  2. pm2: nodejs 用來做 cluster 的工具

2. 範例 CPU Intensive 的 Task

app.service.ts

import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  doHeavyJob(): string {
    let total = 0;
    for (let i = 0; i < 50_000_000; i++) {
      total++;
    }
    return `The result of the CPU intensive task is ${total}`;
  }
}

app.controller.ts

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('heavy')
  doHeavyJob(): string {
    return this.appService.doHeavyJob();
  }
}

3. 使用 loadtest 來做 benchmark

npx loadtest -n 1200 -c 400 -k http://localhost:3000/heavy

總共 latency 是 20 秒左右

總共耗時 71 秒

4. 使用 cluster mode 來處理

primary.ts

import { Logger } from '@nestjs/common';
import * as _cluster from 'cluster';
const cluster = _cluster as unknown as _cluster.Cluster;
import * as os from 'os';
import * as path from 'path';
const cpuCount = os.cpus().length;
const logger = new Logger('Primary');
logger.log({
  message: `The total number of CPUs is ${cpuCount}, primary pid=${process.pid}`,
});
cluster.setupPrimary({
  exec: path.join(__dirname, 'main.js'),
});
for (let i = 0; i < cpuCount; i++) {
  cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
  logger.log({
    messsage: `worker ${worker.process.pid} has been killed with ${signal}, Starting another worker`,
  });
  cluster.fork();
});

5. 使用 cluster mode 來做 benchmark

使用以下指令執行 server

nest start --entryFile primary

使用 loadtest 做 benchmark

npx loadtest -n 1200 -c 400 -k http://localhost:3000/heavy

6. 透過 pm2 來執行 cluster

使用以下指令執行 server

pm2 start dist/main.js -i max --name nest

使用 loadtest 做 benchmark

npx loadtest -n 1200 -c 400 -k http://localhost:3000/heavy

總共 latency 是 3 秒左右

總共耗時 11 秒

worker thread vs cluster

之前有提到要有效去利用 CPU 資源除了使用 cluster 之外

也可以使用 worker thread

其差別在於 worker thread 的內部資料比 cluster mode 更方便去分享資料

所以當每個 thread 資料需要做分享時,適合使用 worker thread

而 cluster mode 適合需要獨立執行的 workload

參考

[1] cluster

[2] pm2

More from this blog

Claude Code 監控秘錄:OpenTelemetry(OTel/OTLP)實戰指南

稟告主公:此乃司馬懿進呈之兵書,詳解如何以 OpenTelemetry 陣法,令臥龍神算之一舉一動盡在掌握,知糧草消耗、察兵器效能、辨戰報異常,使主公運籌帷幄於大帳之中。 為何需要斥候情報? 司馬懿稟告主公: 臥龍神算(Claude Code)乃當世利器,然若無斥候回報,主公便如蒙眼行軍——兵器耗損幾何、糧草消費幾許、哪路斥候出了差錯,一概不知。臣以為,此乃兵家大忌。 無情報之弊,有四: 軍

Feb 19, 202610 min read162
Claude Code 監控秘錄:OpenTelemetry(OTel/OTLP)實戰指南

工程師的 Claude Code 實戰指南:從零開始到高效開發

工程師的 Claude Code 實戰指南:從零開始到高效開發 本文整合 Anthropic 官方 Best Practices 與社群實戰 Tips,帶你由淺入深掌握 Claude Code。 什麼是 Claude Code?為什麼值得學? 如果你還在用「複製程式碼貼到 ChatGPT,再複製答案貼回去」的工作流程,Claude Code 會讓你大開眼界。 Claude Code 是 Anthropic 推出的命令列工具,它直接活在你的 terminal 裡,能夠讀懂你的整個 codeb...

Feb 18, 20265 min read72
工程師的 Claude Code 實戰指南:從零開始到高效開發

System Design Interview Ch 12 Digital Wallet

確立問題與設計範疇 角色對話內容 面試者我們應該只關注兩個數位錢包之間的餘額轉帳操作嗎?我們是否需要擔心其他功能? 面試官讓我們只關注餘額轉帳操作。 面試者該系統需要支援多少 TPS(每秒交易次數)? 面試官讓我們假設是 1,000,000 TPS (每秒 100 萬次交易)。 面試者數位錢包對正確性有嚴格的要求。我們可以假設事務保證 就足夠了嗎? 面試官聽起來不錯。 面試者我們需要證明正確性嗎? 面試官這是一個很好的問題。正確性(Correctness)通常只有在交...

Feb 2, 202610 min read190
System Design Interview Ch 12 Digital Wallet

Claude Code 利用 Event-Driven Hooks 打造自動化開發大腦

在現代 AI 輔助開發中,我們不僅需要 AI 寫程式,更需要它懂規則、記性好,並且能自動處理那些繁瑣的雜事。透過 Claude Code Hooks 機制,我們可以介入 AI 的思考與執行迴圈,實現真正的「人機協作自動化」。 一、 動機與痛點:為什麼你需要介入 AI 的生命週期? 在預設狀態下,Claude Code 雖然強大,但它是「被動」且「無狀態」的,這導致了開發者常遇到以下痛點: 記憶重置 (Session Amnesia): 痛點:每次重啟終端機,AI 就像失憶一樣。 解法:你...

Jan 24, 20266 min read443
Claude Code 利用 Event-Driven Hooks 打造自動化開發大腦
M

MicroFIRE

71 posts