在什麼樣的情況下需要效能提升?
如果我們的程式需要進行重度的計算,而且這個任務無法像 timer, http request 等,可以非同步運行時,我們的 Request 就會被卡住
ex:
const express = require('express'); |
我們寫一個 doWork function,讓它在既定秒數內不斷跑 while 迴圈
這個時如果開兩個 tab 載入頁面,你就會發現第二個載入的頁面會慢非常多,因為 server 還在處理第一個頁面,必須等第一個頁面處理完才會處理第二個頁面
利用 Node.js “Cluster” Mode 多開幾個 process 來幫忙吧!
因為每個 Process 都只能用單核心 CPU 來運行, 透過 Cluster 模組就可以開更多的 Process 來幫忙處理,
而這個Cluster的模組強大的地方在於讓我們只監聽一個Port,加上Master/Worker的概念,當收到請求後就分配給底下的Worker進行處理。
Cluster Manager 負責監控底下 Node Server 的狀態,Cluster Manager 可以開 Node Instance, 關閉 Instance, 送資訊給 Instance
Cluster 如何運作?
他主要是使用 child_process.fork()
產生新的 proccess 用此來與 master_process 溝通。
如圖所示
圖片來源: 【我可以你也可以的Node.js】第二十篇 - Node Cluster 讓你的 Thread 不再孤軍奮戰
預設配發方式
當一個請求進來的時候進到 master process
然後由他去輪流指派 一個 process
。
使用 Cluster
使用 Cluster 時,我們可以使用 cluster.isMaster
屬性去判斷現在是否為 Master Process
const cluster = require('cluster'); |
我們新增一個不會阻塞的 route /fast
,由於我們現在有兩個 process 了,所以當我們開兩個 tab,一個發到 /
,另一個再發到 /fast
,我們可以發現 /fast
直接就返回了,沒有被上個 Request 卡死
既然開 Process 就可以變快,那開好開滿不就超快?
我們這邊可以用 ab
(apache-benchmark) 指令來測試開越多 child process 是否就越好
ab -c 50 -n 500 localhost:3000/fast |
-c
: concurrency 的意思,-c 50
同時保持有 50 Request 還處 pending 的狀態-n
: request 的總數,-n 500
代表總共發 500 個
測試方式:逐步增加 Child Process 和 Request
測試程式:
if (cluster.isMaster) { |
測試 1 個 Child Process
測試指令
ab -c -1 -n -1 localhost:3000/ |
測試結果
測試 2 個 Child Process
測試指令
ab -c -2 -n -2 localhost:3000/ |
測試結果
測試 10 個 Child Process
測試指令
ab -c -10 -n -10 localhost:3000/ |
測試結果
測試 2 個 Child Process 同時處理 10 個 Request
測試指令
ab -c -10 -n -10 localhost:3000/ |
測試結果
我們可以看到,新增一個 Child Process,確實是讓 2 個請求維持在同一時間返回,但是新增到10 個 Child Process 時,面對同時 10 個請求速度卻下降了,然會後最驚人的事,只開兩個 Child Process 卻比開 10 個的快???
Stack Overflow 也有人提出相似問題: Node.js clustering is slower than single threaded mode, 但看起也有沒有結論
PM2
相較與直接用 cluster 模組,在管理 process 方面,社群大多數人會使用 pm2 開源專案,pm2 除了管裡 process 以外還有許多實用的功能,可以參考 Ray Leel 大的 好 pm2, 不用嗎?
安裝:
npm i -g pm2 |
使用方法:
開啟 instance:
-i
後面接希望啟動 instance 的數量, 0 或 max 默認自動偵測 CPU 啟動最大值
pm2 start app.js -i 0 |
顯示管理程序狀態:
pm2 [list|ls|status] |
停止服務:
pm2 stop app_name |
停止並刪除服務:
pm2 delete app_name |
Reference: