這篇文章主要介紹了Node.js中cluster模組的介紹,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下
Node的單線程設計已經沒法更充分的"壓榨"機器性能了,Node新增了一個內置模組cluster,它可以通過一個父進程管理一坨子進程的方式來實現集群的功能,這篇文章主要介紹了深入剖析Node.js cluster模組,有興趣的小夥伴可以參考一下
cluster模組概覽
node實例是單執行緒作業的。在服務端程式設計中,通常會建立多個node實例來處理客戶端的請求,以此提升系統的吞吐率。對這樣多個node實例,我們稱之為cluster(叢集)。
借助node的cluster模組,開發者可以在幾乎不修改原有專案程式碼的前提下,獲得叢集服務帶來的好處。
叢集有以下兩種常見的實作方案,而node自帶的cluster模組,採用了方案二。
方案一:多個node實例多個端口
集群內的node實例,各自監聽不同的端口,再由反向代理實現請求到多個連接埠的分發。
優點:實作簡單,各實例相對獨立,這對服務穩定性有好處。
缺點:增加連接埠佔用,進程之間通訊比較麻煩。
方案二:主程序向子程序轉送請求
群集內,建立一個主程序(master),以及若干個子程序( worker)。由master監聽客戶端連線請求,並依照特定的策略,轉送給worker。
優點:通常只佔用一個端口,通訊相對簡單,轉送策略更靈活。
缺點:實作相對複雜,對主流程的穩定性要求較高。
入門實例
#在cluster模組中,主程式稱為master,子程式稱為worker。
範例如下,建立與CPU數目相同的服務端實例,來處理客戶端請求。注意,它們監聽的都是同樣的連接埠。
// server.js var cluster = require('cluster'); var cpuNums = require('os').cpus().length; var http = require('http'); if(cluster.isMaster){ for(var i = 0; i < cpuNums; i++){ cluster.fork(); } }else{ http.createServer(function(req, res){ res.end(`response from worker ${process.pid}`); }).listen(3000); console.log(`Worker ${process.pid} started`); }
建立批次腳本:./req.sh。
#!/bin/bash # req.sh for((i=1;i<=4;i++)); do curl http://127.0.0.1:3000 echo "" done
輸出如下。可以看到,響應來自不同的進程。
response from worker 23735
response from worker 23731
response from worker 23729
response from worker 23730
cluster模組實作原理
了解cluster模組,主要搞清楚3個問題:
master、worker如何通訊?
多個server實例,如何實作連接埠共用?
多個server實例,來自客戶端的請求如何分發到多個worker?
下面會結合示意圖介紹,原始碼層級的介紹,可以參考 筆者的github。
問題1:master、worker如何通訊
這個問題比較簡單。 master程序透過 cluster.fork() 來建立 worker進程。 cluster.fork() 內部 是透過 child_process.fork() 來建立子程序。
也就是說:
master行程、worker行程是父、子行程的關係。
master進程、woker進程可以透過IPC通道進行通訊。 (重要)
問題2:如何實作連接埠共用
在前面的範例中,多個woker中建立的server監聽了同個連接埠3000。通常來說,多個進程監聽同個端口,系統會報錯。
為什麼我們的例子沒問題呢?
秘訣在於,net模組中,對 listen() 方法進行了特殊處理。根據目前進程是master進程,還是worker進程:
master進程:在該連接埠上正常監聽請求。 (沒做特殊處理)
worker行程:建立server實例。然後透過IPC通道,向master進程發送訊息,讓master進程也建立 server 實例,並在該連接埠上監聽請求。當請求進來時,master程序將請求轉送給worker程序的server實例。
歸納起來,就是:master程序監聽特定端口,並將客戶請求轉送給worker進程。
如下圖所示:
問題3:如何將請求分發到多個worker
每當worker程序建立server實例來監聽請求,都會透過IPC通道,在master上進行註冊。當客戶端請求到達,master會負責將請求轉發給對應的worker。
具體轉送給哪個worker?這是由轉送策略決定的。可以透過環境變數NODE_CLUSTER_SCHED_POLICY設置,也可以在cluster.setupMaster(options)時傳入。
默认的转发策略是轮询(SCHED_RR)。
当有客户请求到达,master会轮询一遍worker列表,找到第一个空闲的worker,然后将该请求转发给该worker。
master、worker内部通信小技巧
在开发过程中,我们会通过 process.on('message', fn) 来实现进程间通信。
前面提到,master进程、worker进程在server实例的创建过程中,也是通过IPC通道进行通信的。那会不会对我们的开发造成干扰呢?比如,收到一堆其实并不需要关心的消息?
答案肯定是不会?那么是怎么做到的呢?
当发送的消息包含cmd字段,且改字段以NODE_作为前缀,则该消息会被视为内部保留的消息,不会通过message事件抛出,但可以通过监听'internalMessage'捕获。
以worker进程通知master进程创建server实例为例子。worker伪代码如下:
// woker进程 const message = { cmd: 'NODE_CLUSTER', act: 'queryServer' }; process.send(message);
master伪代码如下:
worker.process.on('internalMessage', fn);
相关链接
官方文档:https://nodejs.org/api/cluster.html
Node学习笔记:https://github.com/chyingp/nodejs-learning-guide
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
以上是Node.js中cluster模組的介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!