淺談nodejs中建立cluster
cluster叢集
我們知道,nodejs的event loop或者說事件響應處理器是單執行緒的,但是現在的CPU基本上都是多核的,為了充分利用現代CPU多核的特性,我們可以建立cluster,從而使多個子程序來共享同一個伺服器埠。
也就是說,通過cluster,我們可以使用多個子程序來服務處理同一個埠的請求。
先看一個簡單的http server中使用cluster的例子:
const cluster =www.cppcns.com require('cluster'); const http = require('http'); const numCPUs = require('os').cpus().length; if (cluster.isMaster) { console.log(`主程序 ${process.pid} 正在執行`); // 衍生工作程序。 for (let i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit',(worker,程式設計客棧 code,signal) => { console.log(`工作程序 ${worker.process.pid} 已退出`); }); } else { // 工作程序可以共享任何 TCP 連線。 // 在本例子中,共享的是 HTTP 伺服器。 http.createServer((req,res) => { res.writeHead(200); res.end('你好世界\n'); }).listen(8000); console.log(`工作程序 ${process.pid} 已啟動`); }
cluster詳解
cluster模組源自於lib/cluster.js,我們可以通過cluster.fork()來建立子工作程序,用來處理主程序的請求。
cluster中的event
cluster繼承自events.EventEmitter,所以cluster可以傳送和接收event。
cluwww.cppcns.comster支援7中event,分別是disconnect,exit,fork,listening,message,online和setup。
在講解disconnect之前,我們先介紹一個概念叫做IPC,IPC的全稱是Inter-Process Communication,也就是程序間通訊。
IPC主要用來進行主程序和子程序之間的通訊。一個工作程序在建立後會自動連線到它的主程序。 當 'disconnect' 事件被觸發時才會斷開連線。
觸發disconnect事情的原因有很多,可以是主動呼叫worker.disconnect(),也可以是工作程序退出或者被kill掉。
cluster.on('disconnect',(worker) => { console.log(`工作程序 #${worker.id} 已斷開連線`); });
exit事件會在任何一個工作程序關閉的時候觸發。一般用來監測cluster中某一個程序是否異常退出,如果退出的話使用cluster.fork建立新的程序,以保證有足夠多的程序來處理請求。
cluster.on('exit',code,signal) => { console.log('工作程序 %d 關閉 (%s). 重啟中...',worker.process.pid,signal || code); cluster.fork(); });
fork事件會在呼叫cluster.fork方法的時候被觸發。
const timeouts = []; function errorMsg() { console.error('連接出錯'); } cluster.on('fork',(worker) => { timeouts[worker.id] = setTimeout(errorMsg,2000); });
主程序和工作程序的listening事件都會在工作程序呼叫listen方法的時候觸發。
cluster.on('listening',address) => { console.log( `工作程序已連線到 ${address.address}:${address.port}`); });
其中worker代表的是工作執行緒,而address中包含三個屬性:address、 port 和 addressType。 其中addressType有四個可選值:
- 4 (TCPv4)
- 6 (TCPv6)
- -1 (Unix 域 socket)
- 'udp4' or 'udp6' (UDP v4 或 v6)
message事件會在主程序收到子程序傳送的訊息時候觸發。
當主程序生成工作程序時會觸發fork,當工作程序執行時會觸發online。
setupMaster方法被呼叫的時候,會觸發setup事件。
cluster中的方法
cluster中三個方法,分別是disconnect,fork和setupMaster。
cluster.disconnect([callback])
呼叫cluster的disconnect方法,實際上會在cluster中的每個worker中呼叫disconnect方法。從而斷開worker和主程序的連線。
當所有的worker都斷開連線之後,會執行callback。
cluster.fork([env])
fork方法,會從主程序中建立新的子程序。其中env是要新增到程序環境變數的鍵值對。
fork將會返回一個cluster.Worker物件,代表工作程序。
最後一個方法是setupMaster:
cluster.setupMaster([settings])
預設情況下,cluster通過fork方法來建立子程序,但是我們可以通過setupMaster來改變這個行為。通過設定settings變數,我們可以改變後面fork子程序的行為。
我們看一個setupMaster的例子:
const cluster = require('cluster'); cluster.setupMaster({ exec: 'worker.js',args: ['--use','https'],silent: true }); cluster.fork(); // https 工作程序 cluster.setupMaster({ exec: 'worker.js','http'] }); cluster.fork(); // http 工作程序
cluster中的屬性
通過cluster物件,我們可以通過isMaster和isWorker來判斷程序是否主程序。
可以通過worker來獲取當前工作程序物件的引用:
const cluster = require('cluster'); if (cluster.isMaster) { console.log('這是主程序'); cluster.fork(); cluster.fork(); } else if (cluster.isWorker) { console.log(`這是工作程序 #${cluster.worker.id}`); }
可以通過workers來遍歷活躍的工作程序物件:
// 遍歷所有工作程序。 function eachWorker(callback) { for (const id in cluster.workers) { callback(cluster.workers[id]); } } eachWorker((worker) => { workerwww.cppcns.com.send('通知所有工作程序'); });
每個worker都有一個id編號,用來定位該worker。
cluster中的worker
worker類中包含了關於工作程序的所有的公共的資訊和方法。cluster.fork出來的就是worker物件。
worker的事件和cluster的很類似,支援6個事件:disconnect,error,exit,listening,message和online。
worker中包含3個屬性,分別是:id,process和exitedAfterDiswww.cppcns.comconnect。
其中id是worker的唯一標記。
worker中的process,實際上是ChildProcess物件,是通過child_process.fork()來創建出來的。
因為在worker中,process屬於全域性變數,所以我們可以直接在worker中使用process來進行傳送訊息。
exitedAfterDisconnect表示如果工作程序由於 .kill() 或 .disconnect() 而退出的話,值就是true。如果是以其他方式退出的話,返回值就是false。如果工作程序尚未退出,則為 undefined。
我們可以通過worker.exitedAfterDisconnect 來區分是主動退出還是被動退出,主程序可以根據這個值決定是否重新生成工作程序。
cluster.on('exit',signal) => { if (worker.exitedAfterDisconnect === true) { console.log('這是自發退出,無需擔心'); } }); // 殺死工作程序。 worker.kill();
worker還支援6個方法,分別是:send,kill,destroy,disconnect,isConnected,isDead。
這裡我們主要講解一下send方法來發送訊息:
worker.send(message[,sendHandle[,options]][,callback])
可以看到send方法和child_process中的send方法引數其實是很類似的。而本質上,worker.send在主程序中,這會發送訊息給特定的工作程序。 相當於 ChildProcess.send()。在工作程序中,這會發送訊息給主程序。 相當於 process.send()。
if (cluster.isMaster) { const worker = cluster.fork(); worker.send('你好'); } else if (cluster.isWorker) { process.on('message',(msg) => { process.send(msg); }); }
在上面的例子中,如果是在主程序中,那麼可以使用worker.send來發送訊息。而在子程序中,則可以使用worker中的全域性變數process來發送訊息。
總結
使用cluster可以充分使用多核CPU的優勢,希望大家在實際的專案中應用起來。
以上就是淺談nodejs中建立cluster的詳細內容,更多關於nodejs中建立cluster的資料請關注我們其它相關文章!