這次帶給大家剖析Node.js 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);
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上是剖析Node.js cluster模組使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!