您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關(guān)Nodejs-cluster模塊怎么用的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。
Node.js默認(rèn)單進(jìn)程運(yùn)行,對(duì)于32位系統(tǒng)最高可以使用512MB內(nèi)存,對(duì)于64位最高可以使用1GB內(nèi)存。對(duì)于多核CPU的計(jì)算機(jī)來(lái)說(shuō),這樣做效率很低,因?yàn)橹挥幸粋€(gè)核在運(yùn)行,其他核都在閑置。cluster模塊就是為了解決這個(gè)問(wèn)題而提出的。
cluster模塊允許設(shè)立一個(gè)主進(jìn)程和若干個(gè)worker進(jìn)程,由主進(jìn)程監(jiān)控和協(xié)調(diào)worker進(jìn)程的運(yùn)行。worker之間采用進(jìn)程間通信交換消息,cluster模塊內(nèi)置一個(gè)負(fù)載均衡器,采用Round-robin算法協(xié)調(diào)各個(gè)worker進(jìn)程之間的負(fù)載。運(yùn)行時(shí),所有新建立的鏈接都由主進(jìn)程完成,然后主進(jìn)程再把TCP連接分配給指定的worker進(jìn)程。
var cluster = require('cluster'); var os = require('os'); if (cluster.isMaster){ for (var i = 0, n = os.cpus().length; i < n; i += 1){ cluster.fork(); } } else { http.createServer(function(req, res) { res.writeHead(200); res.end("hello world\n"); }).listen(8000); }
上面代碼先判斷當(dāng)前進(jìn)程是否為主進(jìn)程(cluster.isMaster),如果是的,就按照CPU的核數(shù),新建若干個(gè)worker進(jìn)程;如果不是,說(shuō)明當(dāng)前進(jìn)程是worker進(jìn)程,則在該進(jìn)程啟動(dòng)一個(gè)服務(wù)器程序。
上面這段代碼有一個(gè)缺點(diǎn),就是一旦work進(jìn)程掛了,主進(jìn)程無(wú)法知道。為了解決這個(gè)問(wèn)題,可以在主進(jìn)程部署online事件和exit事件的監(jiān)聽(tīng)函數(shù)。
var cluster = require('cluster'); if(cluster.isMaster) { var numWorkers = require('os').cpus().length; console.log('Master cluster setting up ' + numWorkers + ' workers...'); for(var i = 0; i < numWorkers; i++) { cluster.fork(); } cluster.on('online', function(worker) { console.log('Worker ' + worker.process.pid + ' is online'); }); cluster.on('exit', function(worker, code, signal) { console.log('Worker ' + worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal); console.log('Starting a new worker'); cluster.fork(); }); }
上面代碼中,主進(jìn)程一旦監(jiān)聽(tīng)到worker進(jìn)程的exit事件,就會(huì)重啟一個(gè)worker進(jìn)程。worker進(jìn)程一旦啟動(dòng)成功,可以正常運(yùn)行了,就會(huì)發(fā)出online事件。
worker對(duì)象
worker對(duì)象是cluster.fork()的返回值,代表一個(gè)worker進(jìn)程。
它的屬性和方法如下。
(1)worker.id
worker.id返回當(dāng)前worker的獨(dú)一無(wú)二的進(jìn)程編號(hào)。這個(gè)編號(hào)也是cluster.workers中指向當(dāng)前進(jìn)程的索引值。
(2)worker.process
所有的worker進(jìn)程都是用child_process.fork()生成的。child_process.fork()返回的對(duì)象,就被保存在worker.process之中。通過(guò)這個(gè)屬性,可以獲取worker所在的進(jìn)程對(duì)象。
(3)worker.send()
該方法用于在主進(jìn)程中,向子進(jìn)程發(fā)送信息。
if (cluster.isMaster) { var worker = cluster.fork(); worker.send('hi there'); } else if (cluster.isWorker) { process.on('message', function(msg) { process.send(msg); }); }
上面代碼的作用是,worker進(jìn)程對(duì)主進(jìn)程發(fā)出的每個(gè)消息,都做回聲。
在worker進(jìn)程中,要向主進(jìn)程發(fā)送消息,使用process.send(message);要監(jiān)聽(tīng)主進(jìn)程發(fā)出的消息,使用下面的代碼。
process.on('message', function(message) { console.log(message); });
發(fā)出的消息可以字符串,也可以是JSON對(duì)象。下面是一個(gè)發(fā)送JSON對(duì)象的例子。
worker.send({ type: 'task 1', from: 'master', data: { // the data that you want to transfer } });
cluster.workers對(duì)象
該對(duì)象只有主進(jìn)程才有,包含了所有worker進(jìn)程。每個(gè)成員的鍵值就是一個(gè)worker進(jìn)程對(duì)象,鍵名就是該worker進(jìn)程的worker.id屬性。
function eachWorker(callback) { for (var id in cluster.workers) { callback(cluster.workers[id]); } } eachWorker(function(worker) { worker.send('big announcement to all workers'); });
上面代碼用來(lái)遍歷所有worker進(jìn)程。
當(dāng)前socket的data事件,也可以用id屬性識(shí)別worker進(jìn)程。
socket.on('data', function(id) { var worker = cluster.workers[id]; });
cluster模塊的屬性與方法
isMaster,isWorker
isMaster屬性返回一個(gè)布爾值,表示當(dāng)前進(jìn)程是否為主進(jìn)程。這個(gè)屬性由process.env.NODE_UNIQUE_ID決定,如果process.env.NODE_UNIQUE_ID為未定義,就表示該進(jìn)程是主進(jìn)程。
isWorker屬性返回一個(gè)布爾值,表示當(dāng)前進(jìn)程是否為work進(jìn)程。它與isMaster屬性的值正好相反。
fork()
fork方法用于新建一個(gè)worker進(jìn)程,上下文都復(fù)制主進(jìn)程。只有主進(jìn)程才能調(diào)用這個(gè)方法。
該方法返回一個(gè)worker對(duì)象。
kill()
kill方法用于終止worker進(jìn)程。它可以接受一個(gè)參數(shù),表示系統(tǒng)信號(hào)。
如果當(dāng)前是主進(jìn)程,就會(huì)終止與worker.process的聯(lián)絡(luò),然后將系統(tǒng)信號(hào)法發(fā)向worker進(jìn)程。如果當(dāng)前是worker進(jìn)程,就會(huì)終止與主進(jìn)程的通信,然后退出,返回0。
在以前的版本中,該方法也叫做 worker.destroy() 。
listening事件
worker進(jìn)程調(diào)用listening方法以后,“l(fā)istening”事件就傳向該進(jìn)程的服務(wù)器,然后傳向主進(jìn)程。
該事件的回調(diào)函數(shù)接受兩個(gè)參數(shù),一個(gè)是當(dāng)前worker對(duì)象,另一個(gè)是地址對(duì)象,包含網(wǎng)址、端口、地址類型(IPv4、IPv6、Unix socket、UDP)等信息。這對(duì)于那些服務(wù)多個(gè)網(wǎng)址的Node應(yīng)用程序非常有用。
不中斷地重啟Node服務(wù)
重啟服務(wù)需要關(guān)閉后再啟動(dòng),利用cluster模塊,可以做到先啟動(dòng)一個(gè)worker進(jìn)程,再把原有的所有work進(jìn)程關(guān)閉。這樣就能實(shí)現(xiàn)不中斷地重啟Node服務(wù)。
首先,主進(jìn)程向worker進(jìn)程發(fā)出重啟信號(hào)。
workers[wid].send({type: 'shutdown', from: 'master'});
worker進(jìn)程監(jiān)聽(tīng)message事件,一旦發(fā)現(xiàn)內(nèi)容是shutdown,就退出。
process.on('message', function(message) { if(message.type === 'shutdown') { process.exit(0); } });
下面是一個(gè)關(guān)閉所有worker進(jìn)程的函數(shù)。
function restartWorkers() { var wid, workerIds = []; for(wid in cluster.workers) { workerIds.push(wid); } workerIds.forEach(function(wid) { cluster.workers[wid].send({ text: 'shutdown', from: 'master' }); setTimeout(function() { if(cluster.workers[wid]) { cluster.workers[wid].kill('SIGKILL'); } }, 5000); }); };
PM2模塊
PM2模塊是cluster模塊的一個(gè)包裝層。它的作用是盡量將cluster模塊抽象掉,讓用戶像使用單進(jìn)程一樣,部署多進(jìn)程N(yùn)ode應(yīng)用。
// app.js var http = require('http'); http.createServer(function(req, res) { res.writeHead(200); res.end("hello world"); }).listen(8080);
用PM2從命令行啟動(dòng)這段代碼
$ pm2 start app.js -i 4
上面代碼的i參數(shù)告訴PM2,這段代碼應(yīng)該在cluster_mode啟動(dòng),且新建worker進(jìn)程的數(shù)量是4個(gè)。如果i參數(shù)的值是0,那么當(dāng)前機(jī)器有幾個(gè)CPU內(nèi)核,PM2就會(huì)啟動(dòng)幾個(gè)worker進(jìn)程。
如果一個(gè)worker進(jìn)程由于某種原因掛掉了,會(huì)立刻重啟該worker進(jìn)程。
# 重啟所有worker進(jìn)程 $ pm2 reload all
每個(gè)worker進(jìn)程都有一個(gè)id,可以用下面的命令查看單個(gè)worker進(jìn)程的詳情。
$ pm2 show <worker id>
關(guān)閉worker進(jìn)程的時(shí)候,可以部署下面的代碼,讓worker進(jìn)程監(jiān)聽(tīng)shutdown消息。一旦收到這個(gè)消息,進(jìn)行完畢收尾清理工作再關(guān)閉
process.on('message', function(msg) { if (msg === 'shutdown') { close_all_connections(); delete_logs(); server.close(); process.exit(0); } });
感謝各位的閱讀!關(guān)于“Nodejs-cluster模塊怎么用”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。