前文介紹了NodeJs子進程創(chuàng)建和進程間通信,但讓開發(fā)者處理多進程的管理是比較麻煩的事情歌逢,通常開發(fā)者只希望關(guān)注業(yè)務代碼的實現(xiàn)签杈。本文介紹了多進程管理相關(guān)的cluster模塊、工具沽一、負載均衡等盖溺。
相關(guān)文章
- 學習NodeJs多進程(一)
- 學習NodeJs多進程(二)
目錄
- cluster模塊
- 負載均衡
- 進程管理工具
- cluster不適用的場景
cluster模塊
cluster模塊是對多進程創(chuàng)建、消息傳遞铣缠、共享端口的封裝烘嘱。以下為官方的使用示例昆禽,根據(jù)cpu數(shù)量創(chuàng)建工作進程,并監(jiān)聽同一個端口8000
蝇庭。
const cluster = require('cluster')
const http = require('http')
const numCPUs = require('os').cpus().length
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`)
// Fork workers.
for (let i = 0; i < numCPUs; i++) {
cluster.fork()
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`)
})
} else {
// Workers can share any TCP connection
// In this case it is an HTTP server
http.createServer((req, res) => {
res.writeHead(200)
res.end('hello world\n')
}).listen(8000)
console.log(`Worker ${process.pid} started`)
}
在前文介紹的多進程監(jiān)聽同一端口中醉鳖,主進程創(chuàng)建服務器,并將服務器句柄傳遞給子進程哮内,子進程再根據(jù)句柄還原服務器實例盗棵,請求到來時由操作系統(tǒng)調(diào)度機制決定交給哪個進程處理。以上由于保留了多個服務器實例直接監(jiān)聽同一端口北发,會造成資源浪費纹因,并且請求轉(zhuǎn)發(fā)不可控。
cluster模塊中默認以輪詢的方式處理請求琳拨,父進程創(chuàng)建內(nèi)部服務器并監(jiān)聽端口瞭恰,所有請求先經(jīng)過該服務器,再轉(zhuǎn)發(fā)給子進程處理从绘。由于父進程負責轉(zhuǎn)發(fā)寄疏,因此父進程可以指定負載均衡策略,另外父進程不直接處理業(yè)務邏輯僵井,可以保證父進程的穩(wěn)定性陕截。
cluster模塊提供豐富的api用來管理子進程,以下示例為子進程掛掉后自動創(chuàng)建新的進程:
const cluster = require('cluster')
const http = require('http')
cluster.schedulingPolicy = cluster.SCHED_RR
function listen (worker) {
worker.on('message', (msg) => {
console.log(`worker ${worker.process.pid}:`, msg)
})
}
if (cluster.isMaster) {
console.log(`master process ${process.pid} is running`)
for (let i = 0; i < 4; i++) {
cluster.fork()
}
for (const id in cluster.workers) {
listen(cluster.workers[id])
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker process ${worker.process.pid} is exited`)
listen(cluster.fork())
})
} else {
http.createServer((req, res) => {
res.writeHead(200)
res.end('hello world')
process.send('handled request')
}).listen(8000)
console.log(`worker process ${process.pid} is running`)
}
訪問localhost:8000批什,再手動kill掉某一進程农曲,執(zhí)行結(jié)果如下:
master process 8616 is running
worker process 16332 is running
worker process 4624 is running
worker process 8084 is running
worker process 16352 is running
worker 16332: handled request
worker 15172: handled request
worker process 15172 is exited
worker process 2260 is running
worker 16332: handled request
worker 8084: handled request
worker 2260: handled request
可以看到,只要有子進程退出驻债,會自動創(chuàng)建子進程乳规。只要有工作進程存在,就能繼續(xù)處理請求合呐。
負載均衡
cluster模塊提供兩種負載均衡策略
-
cluster.SCHED_RR
輪詢分發(fā)(除Windows外所有平臺的默認方法)暮的,由主進程負責監(jiān)聽端口,接收新連接后再將連接循環(huán)分發(fā)給工作進程淌实。在分發(fā)中使用了一些內(nèi)置技巧防止工作進程任務過載冻辩。
-
cluster.SCHED_NONE
使用操作系統(tǒng)調(diào)度機制,主進程創(chuàng)建監(jiān)聽socket后發(fā)送給感興趣的工作進程拆祈,由工作進程負責直接接收連接恨闪。由于操作系統(tǒng)調(diào)度機制的難以捉摸,可能會使分發(fā)變得不穩(wěn)定放坏。在cluster模塊出現(xiàn)之前咙咽,多進程共同監(jiān)聽同一端口的調(diào)度方式都是用該機制。
使用cluster.schedulingPolicy
可指定以上兩種策略淤年,也可以使用NODE_CLUSTER_SCHED_POLICY
環(huán)境變量钧敞,對應以上的兩種策略的取值為rr
蜡豹、none
。
cluster不支持自定義負載均衡策略犁享,可參考cluster的源碼余素,實現(xiàn)自己的負載均衡策略。根據(jù)cluster模塊源碼學習來理解多進程的負載均衡算法炊昆,文章地址:http://www.cnblogs.com/accordion/p/7207740.html
進程管理工具
在生產(chǎn)環(huán)境中桨吊,除了使用多進程充分利用cpu性能外,還需考慮進程異常退出的自動重啟凤巨,多個工作進程共享資源视乐,以及多進程之間的調(diào)度。cluster模塊只是對多進程創(chuàng)建敢茁、消息傳遞佑淀、共享端口的簡單封裝,下面介紹一些目前成熟的進程管理工具彰檬。
-
Pandora.js 是一個 Node.js 應用監(jiān)控管理器伸刃,它集成了多種類型的能力諸如:監(jiān)控、鏈路追蹤逢倍、調(diào)試捧颅、進程管理等等。它提供多進程模型较雕、多進程管理以及自定義進程擴展能力碉哑。開發(fā)者只需關(guān)注具體的業(yè)務邏輯實現(xiàn)即可。
-
是一個進程管理工具亮蒋,維護一個進程列表扣典,可以用它來管理你的node進程,負責所有正在運行的進程慎玖,并查看node進程的狀態(tài)贮尖,也支持性能監(jiān)控,自動重啟趁怔,負載均衡等功能远舅,而且使用非常簡單。
-
Egg
雖然是企業(yè)級的NodeJs開發(fā)框架痕钢,但集成了egg-cluster
模塊實現(xiàn)多進程的管理,自帶服務管理的cli序六,不需要其他的進程管理工具來管理進程了任连。另外提供Agent進程來處理不適合用多進程處理的場景,如定時任務例诀、websocket等随抠。
cluster不適用的場景
這里的cluster不止指node的cluster模塊裁着,也包括通過第三方庫實現(xiàn)的多進程管理工具。cluster雖然能充分利用服務器cpu資源拱她,提高服務的健壯性二驰,但并不是所有場景都適合用多進程來處理,比如:
-
定時任務
定時任務應該只被一個進程調(diào)用秉沼,如果以多進程的模式啟動桶雀,會造成定時任務的重復執(zhí)行。通常應該單獨創(chuàng)建一個進程來處理定時任務唬复,并且該進程應該保證穩(wěn)定性矗积,在發(fā)生異常錯誤時記錄錯誤而不自動退出。
-
socket.io
socket.io是在websocket上封裝的敞咧,在客戶端未提供websocket功能的基礎(chǔ)上使用xhr polling棘捣、jsonp或forever iframe的方式進行兼容,同時在建立ws連接前往往通過幾次http輪詢確保websocket服務可用休建。在建立連接前的幾次http輪詢?nèi)绻晦D(zhuǎn)發(fā)到了不同的進程乍恐,會導致ws服務連接失敗。socket.io官方提供了
nginx反向代理 + iphash
的方式來保證同一個客戶端的多次請求定位到后端同一個服務進程测砂。關(guān)于socket.io的集群策略茵烈,可參考:https://segmentfault.com/a/1190000009622158- session和內(nèi)存緩存
使用cluster模塊通常是無狀態(tài)應用,因為在進程中緩存的數(shù)據(jù)無法直接與其他進程共享邑彪,理論上可以在主進程上維護統(tǒng)一的緩存數(shù)據(jù)瞧毙,然后子進程從父進程中獲取,但邏輯上比較復雜寄症,并且增加了父進程的負擔宙彪。因此常常使用第三方工具來共享應用狀態(tài),如
redis
有巧。
總結(jié)
本文介紹了cluster模塊和常用的多進程管理工具释漆,希望對想要使用多進程來提升服務的性能和健壯性的小伙伴有一些幫助。
本文參考資源如下: