這次帶給大家剖析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 <p style="text-align: left;">建立批次腳本:./req.sh。 </p><pre class="brush:php;toolbar:false">#!/bin/bash # req.sh for((i=1;i<p style="text-align: left;">輸出如下。可以看到,響應來自不同的進程。 </p><blockquote style="text-align: left;"><p style="text-align: left;">response from worker 23735<br>response from worker 23731<br>response from worker 23729<br>response from worker 23730</p></blockquote><p style="text-align: left;"><span style="color: #ff0000"><strong>cluster模組實作原理</strong></span></p><p style="text-align: left;">了解cluster模組,主要搞清楚3個問題:</p><ol class=" list-paddingleft-2"> <li><p style="text-align: left;">master、worker如何通訊? </p></li> <li><p style="text-align: left;">多個server實例,如何實作連接埠共用? </p></li> <li><p style="text-align: left;">多個server實例,來自客戶端的請求如何分發到多個worker? </p></li> </ol><p style="text-align: left;">下面會結合示意圖介紹,原始碼層級的介紹,可以參考 筆者的github。 </p><p style="text-align: left;"><strong>問題1:master、worker如何通訊</strong></p><p style="text-align: left;">這個問題比較簡單。 master程序透過 cluster.fork() 來建立 worker進程。 cluster.fork() 內部 是透過 child_process.fork() 來建立子程序。 </p><p style="text-align: left;">也就是說:</p><ol class=" list-paddingleft-2"> <li><p style="text-align: left;">master行程、worker行程是父、子行程的關係。 </p></li> <li><p style="text-align: left;">master進程、woker進程可以透過IPC通道進行通訊。 (重要)</p></li> </ol><p style="text-align: left;"><strong>問題2:如何實作連接埠共用</strong></p><p style="text-align: left;">在前面的範例中,多個woker中建立的server監聽了同個連接埠3000。通常來說,多個進程監聽同個端口,系統會報錯。 </p><p style="text-align: left;">為什麼我們的例子沒問題呢? </p><p style="text-align: left;">秘訣在於,net模組中,對 listen() 方法進行了特殊處理。根據目前進程是master進程,還是worker進程:</p><ol class=" list-paddingleft-2"> <li><p style="text-align: left;">master進程:在該連接埠上正常監聽請求。 (沒做特殊處理)</p></li> <li><p style="text-align: left;">worker进程:创建server实例。然后通过IPC通道,向master进程<a href="http://www.php.cn/php/php-send-message.html" target="_blank">发送消息</a>,让master进程也创建 server 实例,并在该端口上监听请求。当请求进来时,master进程将请求转发给worker进程的server实例。</p></li> </ol><p style="text-align: left;">归纳起来,就是:master进程监听特定端口,并将客户请求转发给worker进程。</p><p style="text-align: left;">如下图所示:</p><p style="text-align: left;"><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/061/021/392d7540fb965981c01f575d74dd8f15-0.png?x-oss-process=image/resize,p_40" class="lazy" alt="" style="max-width:90%" style="max-width:90%"></p><p style="text-align: left;"><strong>问题3:如何将请求分发到多个worker</strong></p><p style="text-align: left;">每当worker进程创建server实例来监听请求,都会通过IPC通道,在master上进行注册。当客户端请求到达,master会负责将请求转发给对应的worker。</p><p style="text-align: left;">具体转发给哪个worker?这是由转发策略决定的。可以通过环境变量NODE_CLUSTER_SCHED_POLICY设置,也可以在cluster.setupMaster(options)时传入。</p><p style="text-align: left;">默认的转发策略是轮询(SCHED_RR)。</p><p style="text-align: left;">当有客户请求到达,master会轮询一遍worker列表,找到第一个空闲的worker,然后将该请求转发给该worker。</p><p style="text-align: left;"><strong>master、worker内部通信小技巧</strong></p><p style="text-align: left;">在开发过程中,我们会通过 process.on('message', fn) 来实现进程间通信。</p><p style="text-align: left;">前面提到,master进程、worker进程在server实例的创建过程中,也是通过IPC通道进行通信的。那会不会对我们的开发造成干扰呢?比如,收到一堆其实并不需要关心的消息?</p><p style="text-align: left;">答案肯定是不会?那么是怎么做到的呢?</p><p style="text-align: left;">当发送的消息包含cmd字段,且改字段以NODE_作为前缀,则该消息会被视为内部保留的消息,不会通过message<a href="http://www.php.cn/php/php-tp-incident.html" target="_blank">事件</a>抛出,但可以通过监听'internalMessage'捕获。</p><p style="text-align: left;">以worker进程通知master进程创建server实例为例子。worker伪代码如下:</p><pre class="brush:php;toolbar:false">// woker进程 const message = { cmd: 'NODE_CLUSTER', act: 'queryServer' }; process.send(message);
master伪代码如下:
worker.process.on('internalMessage', fn);
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上是剖析Node.js cluster模組使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!