成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

手把手教你玩轉(zhuǎn)Node中的集群

本篇文章帶大家詳細(xì)了解一下Node.js中的集群,介紹一下cluster 事件,希望對大家有所幫助!

手把手教你玩轉(zhuǎn)Node中的集群

一、介紹

Node 在 v0.8 時直接引入了 cluster 模塊,用以解決多核 CPU 的利用率問題,同時也提供了較完善的 API,用以處理進(jìn)程的健壯性問題。

cluster 模塊調(diào)用 fork 方法來創(chuàng)建子進(jìn)程,該方法與 child_process 中的 fork 是同一個方法。 cluster 模塊采用的是經(jīng)典的主從模型,cluster 會創(chuàng)建一個 master,然后根據(jù)你指定的數(shù)量復(fù)制出多個子進(jìn)程,可以使用cluster.isMaster 屬性判斷當(dāng)前進(jìn)程是 master 還是 worker (工作進(jìn)程)。由 master 進(jìn)程來管理所有的子進(jìn)程,主進(jìn)程不負(fù)責(zé)具體的任務(wù)處理,主要工作是負(fù)責(zé)調(diào)度和管理。

cluster 模塊使用內(nèi)置的負(fù)載均衡來更好地處理線程之間的壓力,該負(fù)載均衡使用了 Round-robin 算法(也被稱之為循環(huán)算法)。當(dāng)使用 Round-robin 調(diào)度策略時,master accepts() 所有傳入的連接請求,然后將相應(yīng)的TCP請求處理發(fā)送給選中的工作進(jìn)程(該方式仍然通過 IPC 來進(jìn)行通信)。 官方使用實(shí)例如下所示

const cluster = require('cluster'); const cpuNums = require('os').cpus().length; const http = require('http');  if (cluster.isMaster) {   for (let i = 0; i < cpuNums; i++){     cluster.fork();   }   // 子進(jìn)程退出監(jiān)聽   cluster.on('exit', (worker,code,signal) => {     console.log('worker process died,id',worker.process.pid)   }) } else {   // 給子進(jìn)程標(biāo)注進(jìn)程名   process.title = `cluster 子進(jìn)程 ${process.pid}`;   // Worker可以共享同一個 TCP 連接,這里是一個 http 服務(wù)器   http.createServer((req, res)=> {     res.end(`response from worker ${process.pid}`);   }).listen(3000);   console.log(`Worker ${process.pid} started`); }

其實(shí),cluster 模塊由 child_process 和 net 模塊的組合應(yīng)用,cluster 啟動時,會在內(nèi)部啟動 TCP 服務(wù)器,在 cluster.fork() 子進(jìn)程時,將這個 TCP 服務(wù)器端 socket 的文件描述符發(fā)送給工作進(jìn)程。如果工作進(jìn)程是通過 cluster.fork() 復(fù)制出來的,那么它的環(huán)境變量里就存在 NODE_UNIQUE_ID,如果工作進(jìn)程中存在 listen() 偵聽網(wǎng)絡(luò)端口的調(diào)用,它將拿到文件描述符,通過 SO_REUSEADDR 端口重用,從而實(shí)現(xiàn)多個子進(jìn)程共享端口。

二、cluster 事件

  • fork:復(fù)制一個工作進(jìn)程后觸發(fā)該事件;

  • online:復(fù)制好一個工作進(jìn)程后,工作進(jìn)程主動發(fā)送一條 online 消息給主進(jìn)程,主進(jìn)程收到消息后,觸發(fā)該事件;

  • listening:工作進(jìn)程中調(diào)用 listen() (共享了服務(wù)器端 Socket)后,發(fā)送一條 listening 消息給主進(jìn)程,主進(jìn)程收到消息后,觸發(fā)該事件;

  • disconnect:主進(jìn)程和工作進(jìn)程之間 IPC 通道斷開后會觸發(fā)該事件;

  • exit:有工作進(jìn)程退出時會觸發(fā)該事件;

  • setup:cluster.setupMaster() 執(zhí)行完后觸發(fā)該事件;

這些事件大多跟 child_process 模塊的事件相關(guān),在進(jìn)程間消息傳遞的基礎(chǔ)上完成的封裝。

cluster.on('fork', ()=> {   console.log('fork 事件... '); })  cluster.on('online', ()=> {   console.log('online 事件... '); })  cluster.on('listening', ()=> {   console.log('listening 事件... '); })  cluster.on('disconnect', ()=> {   console.log('disconnect 事件... '); })  cluster.on('exit', ()=> {   console.log('exit 事件... '); })  cluster.on('setup', ()=> {   console.log('setup 事件... '); })

三、master 與 worker 通信

由以上可知,master 進(jìn)程通過 cluster.fork() 來創(chuàng)建 worker 進(jìn)程,其實(shí),cluster.fork() 內(nèi)部是通過 child_process.fork() 來創(chuàng)建子進(jìn)程。也就是說:master 與 worker 進(jìn)程是父、子進(jìn)程的關(guān)系;其跟 child_process 創(chuàng)建的父子進(jìn)程一樣是通過 IPC 通道進(jìn)行通信的。

IPC 的全稱是 Inter-Process Communication,即進(jìn)程間通信,進(jìn)程間通信的目的是為了讓不同的進(jìn)程能夠互相訪問資源并進(jìn)行協(xié)調(diào)工作。Node 中實(shí)現(xiàn) IPC 通道的是管道(pipe)技術(shù),具體實(shí)現(xiàn)由 libuv 提供,在 Windows 下由命名管道(named pipe)實(shí)現(xiàn),*nix 系統(tǒng)則采用 Unix Domain Socket 實(shí)現(xiàn)。其變現(xiàn)在應(yīng)用層上的進(jìn)程間通信只有簡單的 message 事件和 send 方法,使用十分簡單。

手把手教你玩轉(zhuǎn)Node中的集群

父進(jìn)程在實(shí)際創(chuàng)建子進(jìn)程之前,會創(chuàng)建 IPC 通道并監(jiān)聽它,然后才真正創(chuàng)建出子進(jìn)程,并通過環(huán)境變量(NODE_CHANNEL_FD)告訴子進(jìn)程這個 IPC 通道的文件描述符。子進(jìn)程在啟動過程中,根據(jù)文件描述符去連接這個已存在的 IPC 通道,從而完成父子進(jìn)程之間的連接。

手把手教你玩轉(zhuǎn)Node中的集群

建立連接之后的父子進(jìn)程就可以進(jìn)行自由通信了。由于 IPC 通道是用命名管道或 Domain Socket 創(chuàng)建的,它們與網(wǎng)絡(luò) socket 的行為比較類似,屬于雙向通信。不同的是它們在系統(tǒng)內(nèi)核中就完成了進(jìn)程間的通信,而不用經(jīng)過實(shí)際的網(wǎng)絡(luò)層,非常高效。在 Node 中,IPC 通道被抽象為 Stream 對象,在調(diào)用 send 時發(fā)送數(shù)據(jù)(類似于 write ),接收到的消息會通過 message 事件(類似于 data)觸發(fā)給應(yīng)用層。

master 和 worker 進(jìn)程在 server 實(shí)例的創(chuàng)建過程中,是通過 IPC 通道進(jìn)行通信的,那會不會對我們的開發(fā)造成干擾呢?比如,收到一堆其實(shí)并不需要關(guān)心的消息?答案肯定是不會?那么是怎么做到的呢?

Node 引入進(jìn)程間發(fā)送句柄的功能,send 方法除了能通過 IPC 發(fā)送數(shù)據(jù)外,還能發(fā)送句柄,第二個參數(shù)為句柄,如下所示

child.send(meeage, [sendHandle])

句柄是一種可以用來標(biāo)識資源的引用,它的內(nèi)部包含了指向?qū)ο蟮奈募枋龇@缇浔梢杂脕順?biāo)識一個服務(wù)器端 socket 對象、一個客戶端 socket 對象、一個 UDP 套接字、一個管道等。 那么句柄發(fā)送跟我們直接將服務(wù)器對象發(fā)送給子進(jìn)程有沒有什么差別?它是否真的將服務(wù)器對象發(fā)送給子進(jìn)程?

其實(shí) send() 方法在將消息發(fā)送到 IPC 管道前,將消息組裝成兩個對象,一個參數(shù)是 handle,另一個是 message,message 參數(shù)如下所示

{   cmd: 'NODE_HANDLE',   type: 'net.Server',   msg: message }

發(fā)送到 IPC 管道中的實(shí)際上是要發(fā)送的句柄文件描述符,其為一個整數(shù)值。這個 message 對象在寫入到 IPC 管道時會通過 JSON.stringify 進(jìn)行序列化,轉(zhuǎn)化為字符串。子進(jìn)程通過連接 IPC 通道讀取父進(jìn)程發(fā)送來的消息,將字符串通過 JSON.parse 解析還原為對象后,才觸發(fā) message 事件將消息體傳遞給應(yīng)用層使用。在這個過程中,消息對象還要被進(jìn)行過濾處理,message.cmd 的值如果以 NODE_ 為前綴,它將響應(yīng)一個內(nèi)部事件 internalMessage ,如果 message.cmd 值為 NODE_HANDLE,它將取出 message.type 值和得到的文件描述符一起還原出一個對應(yīng)的對象。這個過程的示意圖如下所示

手把手教你玩轉(zhuǎn)Node中的集群

在 cluster 中,以 worker 進(jìn)程通知 master 進(jìn)程創(chuàng)建 server 實(shí)例為例子。worker 偽代碼如下:

// woker進(jìn)程 const message = {   cmd: 'NODE_CLUSTER',   type: 'net.Server',   msg: message }; process.send(message);

master 偽代碼如下:

worker.process.on('internalMessage', fn);

四、如何實(shí)現(xiàn)端口共享

在前面的例子中,多個 woker 中創(chuàng)建的 server 監(jiān)聽了同個端口 3000,通常來說,多個進(jìn)程監(jiān)聽同個端口,系統(tǒng)會報 EADDRINUSE 異常。為什么 cluster 沒問題呢?

因?yàn)楠?dú)立啟動的進(jìn)程中,TCP 服務(wù)器端 socket 套接字的文件描述符并不相同,導(dǎo)致監(jiān)聽到相同的端口時會拋出異常。但對于 send() 發(fā)送的句柄還原出來的服務(wù)而言,它們的文件描述符是相同的,所以監(jiān)聽相同端口不會引起異常。

這里需要注意的是,多個應(yīng)用監(jiān)聽相同端口時,文件描述符同一時間只能被某個進(jìn)程所用,換言之就是網(wǎng)絡(luò)請求向服務(wù)器端發(fā)送時,只有一個幸運(yùn)的進(jìn)程能夠搶到連接,也就是說只有它能為這個請求進(jìn)行服務(wù),這些進(jìn)程服務(wù)是搶占式的。

五、如何將請求分發(fā)到多個worker

  • 每當(dāng) worker 進(jìn)程創(chuàng)建 server 實(shí)例來監(jiān)聽請求,都會通過 IPC 通道,在 master 上進(jìn)行注冊。當(dāng)客戶端請求到達(dá),master 會負(fù)責(zé)將請求轉(zhuǎn)發(fā)給對應(yīng)的 worker;
  • 具體轉(zhuǎn)發(fā)給哪個 worker?這是由轉(zhuǎn)發(fā)策略決定的,可以通過環(huán)境變量 NODE_CLUSTER_SCHED_POLICY 設(shè)置,也可以在 cluster.setupMaster(options) 時傳入,默認(rèn)的轉(zhuǎn)發(fā)策略是輪詢(SCHED_RR);
  • 當(dāng)有客戶請求到達(dá),master 會輪詢一遍 worker 列表,找到第一個空閑的 worker,然后將該請求轉(zhuǎn)發(fā)給該worker;

六、pm2 工作原理

pm2 是 node 進(jìn)程管理工具,可以利用它來簡化很多 node 應(yīng)用管理的繁瑣任務(wù),如性能監(jiān)控、自動重啟、負(fù)載均衡等。

pm2 自身是基于 cluster 模塊進(jìn)行封裝的, 本節(jié)我們主要 pm2 的 Satan 進(jìn)程、God Daemon 守護(hù)進(jìn)程 以及兩者之間的進(jìn)程間遠(yuǎn)程調(diào)用 RPC。

撒旦(Satan),主要指《圣經(jīng)》中的墮天使(也稱墮天使撒旦),被看作與上帝的力量相對的邪惡、黑暗之源,是God 的對立面。

手把手教你玩轉(zhuǎn)Node中的集群

其中 Satan.js 提供程序的退出、殺死等方法,God.js 負(fù)責(zé)維持進(jìn)程的正常運(yùn)行,God 進(jìn)程啟動后一直運(yùn)行,相當(dāng)于 cluster 中的 Master進(jìn)程,維持 worker 進(jìn)程的正常運(yùn)行。

RPC(Remote Procedure Call Protocol)是指遠(yuǎn)程過程調(diào)用,也就是說兩臺服務(wù)器A,B,一個應(yīng)用部署在A 服務(wù)器上,想要調(diào)用 B 服務(wù)器上應(yīng)用提供的函數(shù)/方法,由于不在一個內(nèi)存空間,不能直接調(diào)用,需要通過網(wǎng)絡(luò)來表達(dá)調(diào)用的語義和傳達(dá)調(diào)用的數(shù)據(jù)。同一機(jī)器不同進(jìn)程間的方法調(diào)用也屬于 rpc 的作用范疇。 執(zhí)行流程如下所示

手把手教你玩轉(zhuǎn)Node中的集群

每次命令行的輸入都會執(zhí)行一次 satan 程序,如果 God 進(jìn)程不在運(yùn)行,首先需要啟動 God 進(jìn)程。然后根據(jù)指令,Satan 通過 rpc 調(diào)用 God 中對應(yīng)的方法執(zhí)行相應(yīng)的邏輯。

pm2 start app.js -i 4 為例,God 在初次執(zhí)行時會配置 cluster,同時監(jiān)聽 cluster 中的事件:

// 配置cluster cluster.setupMaster({   exec : path.resolve(path.dirname(module.filename), 'ProcessContainer.js') });  // 監(jiān)聽cluster事件 (function initEngine() {   cluster.on('online', function(clu) {     // worker進(jìn)程在執(zhí)行     God.clusters_db[clu.pm_id].status = 'online';   });      // 命令行中 kill pid 會觸發(fā)exit事件,process.kill不會觸發(fā)exit   cluster.on('exit', function(clu, code, signal) {     // 重啟進(jìn)程 如果重啟次數(shù)過于頻繁直接標(biāo)注為stopped     God.clusters_db[clu.pm_id].status = 'starting';     // 邏輯     // ...   }); })();

在 God 啟動后, 會建立 Satan 和 God 的rpc鏈接,然后調(diào)用 prepare 方法,prepare 方法會調(diào)用 cluster.fork 來完成集群的啟動

God.prepare = function(opts, cb) {   // ...   return execute(opts, cb); };  function execute(env, cb) {   // ...   var clu = cluster.fork(env);   // ...   God.clusters_db[id] = clu;      clu.once('online', function() {     God.clusters_db[id].status = 'online';     if (cb) return cb(null, clu);     return true;   });   return clu; }

七、總結(jié)

本文從 cluster 的基本使用、事件,到 cluster 的基本實(shí)現(xiàn)原理,再到 pm2 如何基于 cluster 進(jìn)行進(jìn)程管理,帶你從入門到深入原理以及了解其高階應(yīng)用,希望對你有幫助。

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
YES4444视频在线观看| 日韩精品无码熟人妻视频 | 草莓丝瓜芭乐鸭脖奶茶搭配食物| 成AV人电影在线观看| 国产成人综合一区人人| 国产综合无码一区二区辣椒| 久久成人A毛片免费观看网站| 美女裸露双奶头尿口无遮挡网站 | AⅤ精品一区二区三区| 成人欧美一区二区三区黑人牛| 国产成人丝袜视频在线观看| 护士人妻HD中文字幕| 六十路七十路熟女乱码| 欧美精品亚洲精品日韩传电影| 日日躁夜夜躁狠狠躁超碰97| 亚洲AV成人无码影视网| 艳妇臀荡乳欲伦交换H漫画小说| 999精品国产人妻无码系列| 俄罗斯女人与马Z00Z视频| 国产午夜鲁丝片AV无码免费| 久久五月丁香中文字幕| 强壮公弄得我次次高潮| 无码毛片视频一区二区三区| 亚洲色欲色欲综合网站色偷偷| AV一区二区三区| 国产精品VA在线观看无码| 久久精品中文字幕无码| 全部免费特黄特色大片| 贪婪洞窟H5双修流攻略小说 | 铜铜铜铜铜铜铜好-深色| 亚洲欧美精品一中文字幕| M豆传媒有限公司观看| 国产精品沙发系列| 美女露内裤扒开腿让男人桶无遮挡 | 八戒网站免费观看视频| 国产无人区一码二码三码MBA| 乱熟女高潮一区二区| 色欲香天天综合网站| 亚洲人成网线在线播放VA| 白嫩的18SEX少妇HD| 国内女人喷潮完整视频| 欧美人与动性XXXXX交性| 午夜理论影院第九电影院| 中字年轻漂亮的儿媳2| 豆国产93在线 | 亚洲| 久久精品国产精品亚洲下载| 日韩精品人成在线播放| 亚洲色大成网站WWW在线| 粗大的内捧猛烈进出动态图 | 国产精品午夜小视频观看| 麻豆我精产国品一二三产区区别| 熟女精品视频一区二区三区| 影视先锋AV资源噜噜| 国产成人无码精品久久久小说| 久久亚洲日韩成人无码导航| 婷婷五月综合色视频| 18禁又污又黄又爽的网站不卡 | 厨房里抱着岳丰满大屁股| 久久久久久久精品成人热小说| 熟妇高潮一区二区麻豆Av渉谷| 伊人热热久久原色播放WWW| 国产成网站18禁止久久影院| 女人18毛片A级毛片免费视频| 亚洲 日韩 激情 无码 中出| XOXOXO性ⅩYY欧美人与人| 精品久久久久久无码国产| 少妇厨房愉情理伦片免费| 自由 日本语 热 亚洲人| 国内精品宾馆在线精品酒店| 日本Α片无遮挡在线观看| 一二三四视频社区在线播放中国| 国产白浆喷水在线视频| 欧美丰满熟妇性XXXX偷拍偷拍| 亚洲AV无码专区成人网址| 成人国产精品一区二区视频 | 99福利资源久久福利资源| 加勒比一本HEYZO高清视频| 色欲人妻AAAAAAA无码| 50岁熟妇的呻吟声对白| 久久不见久久见WWW免费| 无码人妻精品中文字幕不卡| YY6080理AAA级伦大片| 久久综合色一综合色88| 亚洲爆乳成AV人在线视菜奈实| 东京热无码AV一区二区| 欧美激情在线播放| 永久免费不卡在线观看黄网站 | 欧美丰满熟妇XXXX性PPX人| 亚洲综合AV永久无码精品一区二| 国产内射爽爽大片视频社区在线| 日产无人区一线二线三线新版| 重囗味sm在线观看无码| 久久精品卫校国产小美女| 亚洲AV日韩综合一区久热| 国产成人猛男69精品视频| 人妻精品丝袜一区二区无码AV| 中年人妻丰满AV无码久久不卡| 精品久久久无码中字| 午夜无码大尺度福利视频| 国产7色在线 | 国产| 日本高清色WWW在线安全| A区B区C区D区乱码| 免费看美女脱精光的网站| 亚洲字幕AV一区二区三区四区| 黑人勃起太大进不去| 香蕉成人伊视频在线观看| 国产白丝JK捆绑束缚调教视频| 日本XXXX裸体XXXX| あざらしそふと官网| 欧美成人影院亚洲综合图| 综合无码一区二区三区 | 最新欧美精品一区二区三区| 久久亚洲精品成人AV无码网站| 亚洲欧美精品午睡沙发| 黑人异族巨大巨大巨粗| 性色av无码人妻少妇肥臀| 国产美女露脸口爆吞精| 无码无套少妇毛多69XXX| 国产精品18久久久久久麻辣| 唐人社视频呦一区二区| 国产成人亚洲精品| 玩弄人妻少妇500系列网址| 国产A国产片国产| 熟女俱乐部五十路二区AV| 动漫高H纯肉无码视频在线观看 | 国产精品国产三级国产专I| 天堂AⅤ大芭蕉伊人AV| 国产成人涩涩涩视频在线观看 | 无码高潮爽到爆的喷水视频APP| 国产成人蜜桃AV无码永久免费| 色婷婷五月综合亚洲小说| 大象成品W灬源码1| 十八禁无码精品A∨在线观看| 公司办公室的秘书3| 未满十八岁的请自动离开| 国产精品视频免费一区二区| 性色欲网站人妻丰满中文久久不卡| 国产喷水1区2区3区咪咪爱AV| 香蕉97超级碰碰碰视频| 黄 色 视 频 在 线 免费观| 亚洲精品卡一卡2卡3卡4卡| 精品无码久久久久久久久| 艳妇乳肉豪妇荡乳ⅩXX| 免费毛片45分钟| CHINESE农村野外XXXXVIDEOS| 强壮公的侵犯让我高潮不断| 岛国AV动作片免费观看| 无码人妻aⅴ一区二区三区99| 国产性生大片免费观看性| 亚洲欧美成人AⅤ在线专区| 久久婷婷色综合老司机| 99国产精品久久久久久久成人热 | XXXCHINESE国产HD| 色欲AV浪潮AV蜜臀AⅤ| 国产乱妇乱子在线播放视频| 亚洲国产区男人本色| 乱人伦中文无码视频| YY8090理论三级在线观看| 天堂AV亚洲ITV在线AⅤ| 韩国19禁无遮挡啪啪无码网站| 夜夜香夜夜摸夜夜添视频| 欧美另类VIDEOSSEXO潮| 丰满少妇被猛烈进入| 亚洲 欧美 国产 日韩 精品| 久久久精品无码中文天美| A阿V天堂亚洲阿∨天堂在线| 少妇的BBW性大片| 好大好厉害我接了一个顾客| 伊人伊成久久人综合 成人| 情侣过夜的男生会忍住吗| 国产精品边做奶水狂喷无码| 亚洲精品无码不卡在线播HE| 免费网站正能量WWW正能量| 厨房里的激战2李明人物介绍| 亚洲AV蜜桃无码精品无码| 美美女高清毛片视频免费观看| 成人女人爽到高潮的Av在线| 亚洲AV麻豆AⅤ无码电影 | 精品久久久久久综合日本| 50岁熟妇的呻吟声对白| 天天爽夜夜爽人人爽一区二区| 精品人妻一区二区三区视频 | 欧美成人看片一区二区三区尤物| 高雅人妻被迫沦为玩物| 亚洲欧洲中文日韩AV乱码| 欧洲免费无线码在线一区| 国产精品无码久久久久成人影院| 亚洲一级 片内射欧美乱强| 人人妻人人澡人人爽人人精品97 | 和朋友换娶妻一起换着高清| 18禁全彩肉肉无遮挡| 婷婷色香五月综合激激情| 久久亚洲AV成人无码国产电影| 处破初破苞一区二区三区| 亚洲人妻免费视频| 日韩免费无码专区精品观看 | 无码AV中文字幕出轨人妻| 久久夜色精品国产欧美乱| 高H日本视频一区| 伊人久久大香线蕉AV一区|