iT邦幫忙

1

【我可以你也可以的Node.js】第二十篇 - Node Cluster 讓你的 Thread 不再孤軍奮戰

我們都知道 Node 是一個 single thread 並且非同步的語言,
那...假使面臨排山倒海的使用者請求時你能想像那一個 thread 孤軍奮戰的感受嗎?

沒有 ! 你只想到你自己。(好久以前的梗)

所以後來官方提出了這個模組,好讓你可以開啟更多的 process 去減輕那個可憐 Thread 的負擔~
避免以下經典動圖的發生。

這讓我想到我上一支手機 Sony Z5P 擁有當年的旗艦 CPU ,在遊戲效能上根本爛到炸,標榜八核心但是實際上只有 4 顆小核心在跑 ,只有在跑分的時候另外四顆大核心才會拋頭露面刷存在感... (後來以 Root 自行改設定才解決)


此篇學習目標 ◑ω◐ :

  1. Cluster 他怎麼運作的
  2. 實戰在 Hello World
  3. 使用 pm2 讓管理 cluster 更容易

Cluster 他怎麼運作的?

他主要是使用 child_process.fork() 產生新的 proccess 藉此與父進程溝通。
而 Cluster 由兩種分配方式決定如何分配進來的請求。
而這兩種都是經由 master process 傾聽一個 port 然後分配到不同的 process
如圖所示

第一種配發方式

The first one (and the default one on all platforms except Windows), is the round-robin approach, where the master process listens on a port, accepts new connections and distributes them across the workers in a round-robin fashion, with some built-in smarts to avoid overloading a worker process.

是經由 round-robin approach 來決定 ,簡單來說就有點像是老師分派值日生擦黑板,前提是一天只有一件事就是擦黑板且一天只需要擦一次就可以換下一個人。
所以就是當一個請求進來的時候進到 master process 然後由他去輪流指派 一個 process 的概念。(有錯或是舉例錯誤請糾正我)

Note:
除了 Windows 之外其餘都是預設第一種配發方式。
就你最特別這樣。

第二種配發方式

The second approach is where the master process creates the listen socket and sends it to interested workers. The workers then accept incoming connections directly.

簡單來說一樣是由 master process 監聽接口,然後直接配發到有興趣的 process ,就是誰有興趣就配給誰。

在現實生活中感覺可以徵求意見,但是在這邊其實我不知道這個機制要如何知道誰有興趣誰沒興趣,如果有人知道的可以跟我分享一下實際案例,感恩。
如果你也不知道也沒關係我看完也是一個...

官方還特地說明了第二種配發方式

The second approach should, in theory, give the best performance. In practice however, distribution tends to be very unbalanced due to operating system scheduler vagaries. Loads have been observed where over 70% of all connections ended up in just two processes, out of a total of eight.

理論上,第二種方式效能會是最好的,但是實際上會造成其實負載平衡很不平衡的狀況,假使在高併發的情況下總共有八個 process 但卻會有 70% 的連線都只會落在兩個 proccess 在處理。
讓我感覺到能者過勞死的悲痛。
俗話說的好...

你強,你來。


實戰在 Hello World

我們用之前 第二篇 寫的 Hello world 和官方給的範例來實測看看差別。
我這邊使用 loadtest 這工具來簡單測試一下。

single thread


實測結果: 平均 22 ms 的處理時間

cluster multi-core systems

官方 Hello world 範例

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

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

  // Fork workers.
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
  });
} else {
  // Workers can share any TCP connection
  // In this case it is an HTTP server
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}

實測結果: 平均 26.9 ms 的處理時間

嗯...

跟我想像中的結果不一樣啊啊啊啊啊! 目前我還在尋找這未知的謎題...
目前我的猜測是因為其實他一下就做完了,然後我開了 cluster 導致他要花時間去分配,造成處理時間更長。
另外看了 stack overflow 的這個討論串
Node.js clustering is slower than single threaded mode
但是還是有點違背我的想像 ~~
如果你知道為什麼拜託告訴我。


使用 pm2 讓管理 cluster 更容易

我另外看了一下好像大多數人不會直接使用原生的 cluster 而是使用這個 pm2 因為設定簡單,然後...好像弄的很不錯(?)

用法很簡單就是
pm2 start -i <數量> --name <tagName> <path>

然後我再次的挑戰上面那個謎題

詳細用法我這邊就不再贅述有興趣可以自行看官方文件唷~

實測結果: 平均 13.4 ms 的處理時間

這才是我要的結果xDDD
至於原因嘛...可能是還有更多設定方面和處理其實不太一樣,導致效能受影響(?)

所以我覺得...嗯...我還是直接用 pm2 好了 (X

如果有興趣研究的可以跟我說...我可以聽你的研究成果 xD


結語

另外看到滿多人提說其實很不建議使用這種方式來做 load balance ,原因是如上面所講的這個機制是透過 master process 來傾聽一個 port 再去分配 worker ,那其實透過 Nginx 來做 LB 然後還有各自的 port 效能來得更優異。

我發現之後開開心心的想說可以用在我前幾週發的麥當勞報報自動領取的 server,殊不知我一看我 aws 的目前使用配置...

沒錯...就是 1 配個...毛? XDDD

感謝收看。


1 則留言

1
fillano
iT邦超人 1 級 ‧ 2020-08-15 17:21:58

我是用過cluster來做批次轉檔之類的,的確有比較快。

Robin iT邦新手 4 級 ‧ 2020-08-15 23:59:59 檢舉

嗯嗯 我後來把 cluster 用在其他運算時間需要比較久的,確實也比較快/images/emoticon/emoticon07.gif

我要留言

立即登入留言