阿Han

文字是留下記錄的一種媒介,將知識吸收轉化後輸出成文字進行保存。 ☕️ https://liker.land/willhanchen/civic

使用Nodejs Cluster打破單線程的限制

發布於

由於Javascript本身設計就適合於單線程的應用, 但一般後端應用程式都會支援多個服務來處理client的請求, nodejs中也提供了cluster模組來達成此功能。

Cluster的原理很簡單,由於每個Process都只能用單核心的CPU來運行,那麼就多開幾個來幫忙處理吧! 而這個Cluster的模組強大的地方在於讓我們只監聽一個Port,加上Master/Worker的概念,當收到請求後就分配給底下的Worker進行處理。


這樣有什麼好處? 遇到尖峰時刻時,我們可以妥善利用多核的優勢,避免有些CPU閒置造成浪費。

如何實做?

根據系統的cpu數量建立N個worker來進行處理。

// server.js
const cluster = require('cluster');
const cpuNums = require('os').cpus().length;
const http = require('http');
if (cluster.isMaster) {
    console.info(`cpu: ${cpuNums}`);
    for (var i = 0; i < cpuNums; i++) {
        cluster.fork();
    }
} else {
    http.createServer(function(req, res) {
        res.end(`response from worker ${process.pid}`);
    }).listen(5000);
    console.log(`Worker ${process.pid} started`);
}

建立測試腳本

for ((i = 1; i <= 8; i++)); do
    curl <http://127.0.0.1:5000>
    echo ""
done

輸出如下, 可以看到response來自不同的worker:

response from worker 7872
response from worker 7878
response from worker 7886
response from worker 7893
response from worker 7853
response from worker 7860
response from worker 7855
response from worker 7866

如何將請求分發到多個worker

每個worker建立時都會於master上註冊並建立IPC通道, 而客戶端請求到達時, master會負責將請求分配給worker。

這裡可能會有疑問是這些請求是如何被分配的?採取什麼策略?

預設的分配策略是輪詢的方式, 當請求到達時, master會輪詢一遍worker列表, 看誰有空閒就將請求分配給該worker進行處理。


另外也支援無分配策略但這種方式可能會造成搶食現象的競爭問題。

可以透過環境變數NODE_CLUSTER_SCHED_POLICY設定, 也可以在cluster.setupMaster(options)時傳入。

process之間的通訊


由於各個process無法共享資源, 但可以藉由IPC通訊方式讓master與worker之間進行通信, 基本用法如下:

// worker 發送訊息
process.send('讀取訊息');
// master 接收消息 -> 處理 -> 回應
cluster.on('online', function (worker) {
     // worker建立時,開始監聽message事件
     cluster.workers[id].on('message', function(data) {
          // 處理來自worker發送的資料
          // 回傳給worker
          cluster.workers[id].send('result')
     });
});

延伸閱讀: 試玩nodejs-worker-threads

喜歡我的文章嗎?
別忘了給點支持與讚賞,讓我知道創作的路上有你陪伴。

CC BY-NC-ND 2.0 版權聲明
1

看不過癮?

一鍵登入,即可加入全球最優質中文創作社區