淺談node中的cluster集群
結(jié)論
雖然平常通過設(shè)置為CPU進程數(shù)的工作進程,但是可以超過這個數(shù),并且并不是主進程先創(chuàng)建
if (cluster.isMaster) { // 循環(huán) fork 任務(wù) CPU i5-7300HQ 四核四進程 for (let i = 0; i < 6; i++) { cluster.fork() } console.log(chalk.green(`主進程運行在${process.pid}`)) } else { app.listen(1314) // export app 一個 Koa 服務(wù)器的實例 console.log(chalk.green(`子進程運行在${process.pid}`)) } #子進程運行在17768 #子進程運行在5784 #子進程運行在11232 #子進程運行在7904 #主進程運行在12960 #子進程運行在4300 #子進程運行在16056
在主進程中 cluster 表示主進程(用于監(jiān)聽、發(fā)送事件), process 是本身的進程,worker 表示子進程,通過 cluster.workers 獲取
在子進程中 process 表示子進程(用于監(jiān)聽、發(fā)送事件),也可以通過 cluster.worker 表示當(dāng)前子進程
cluster.worker.process 等價于 process(在子進程中)
主進程子進程相互通信
- cluster 用于監(jiān)聽 process(child) 子進程觸發(fā)的各種事件
- worker 在主進程中獲取,用于和自身通信。當(dāng)子進程觸發(fā)事件時,會返回當(dāng)前的 worker 以及相關(guān)的信息到主進程相應(yīng)的事件中
- process(parent) 主進程本身的進程實例,在通信過程中基本沒有用到
- process(child) 子進程本身的實例,只能在子進程獲取用于監(jiān)聽自身的事件
可見主進程與子進程通過這樣一個三角關(guān)系互相通信,其中 cluster 和 worker 是在主進程中獲取的,process(child) 是子進程。 cluster 通過操作 worker 通知子進程,子進程本身和 cluster 進行通信。為什么要這樣設(shè)計呢?因為子進程會有多個,只有通過 worker 才能選擇和哪個進程通信
子進程的調(diào)度策略 cluster.schedulingPolicy
調(diào)度策略,包括循環(huán)計數(shù)的 cluster.SCHED_RR,以及由操作系統(tǒng)決定的cluster.SCHED_NONE。 這是一個全局設(shè)置,當(dāng)?shù)谝粋€工作進程被衍生或者調(diào)動cluster.setupMaster()時,都將第一時間生效。除Windows外的所有操作系統(tǒng)中,SCHED_RR都是默認(rèn)設(shè)置。只要libuv可以有效地分發(fā)IOCP handle,而不會導(dǎo)致嚴(yán)重的性能沖擊的話,Windows系統(tǒng)也會更改為SCHED_RR。cluster.schedulingPolicy 可以通過設(shè)置NODE_CLUSTER_SCHED_POLICY環(huán)境變量來實現(xiàn)。這個環(huán)境變量的有效值包括"rr" 和 "none"。
RR 即 Round-Robin 輪詢調(diào)度,即每個子進程的獲取的事件的機會是均等的,這是除 windows以外默認(rèn)的。而 windows 下的調(diào)度策略很詭異,見下圖。目前并沒有相關(guān) API 可以設(shè)置調(diào)度策略的算法,node 只為我們提供了兩個值
進程調(diào)度算法.png
測試數(shù)據(jù)為 1000次 并發(fā)請求,重復(fù)測試20次,在windows下的表現(xiàn)情況??梢?windows 的調(diào)度算法表現(xiàn)的雜亂無章。如果是 RR 算法四條進程的調(diào)度應(yīng)該處于同一橫線上。暫時沒在本地搭建 linux 環(huán)境,有條件的同學(xué)可以協(xié)助測試一波。
cluster的調(diào)度算法目前至于系統(tǒng)有關(guān)
多進程間的鑒權(quán)問題
注意:Node.js不支持路由邏輯。因此在設(shè)計應(yīng)用時,不應(yīng)該過分依賴內(nèi)存數(shù)據(jù)對象(如sessions和login等)。由于各工作進程是獨立的進程,它們可以根據(jù)需要隨時關(guān)閉或重新生成,而不影響其他進程的正常運行。只要有存活的工作進程,服務(wù)器就可以繼續(xù)處理連接。如果沒有存活的工作進程,現(xiàn)有連接會丟失,新的連接也會被拒絕。Node.js不會自動管理工作進程的數(shù)量,而應(yīng)該由具體的應(yīng)用根據(jù)實際需要來管理進程池。
文檔中已明確說明了,每一個工作進程都是獨立的,并且互相之間除了能夠進行通信外,沒有辦法共享內(nèi)存。所以在設(shè)計鑒權(quán)的時候,有兩種方法
- 通過共有的主進程存儲鑒權(quán)信息,每次前端提交帳號密碼,授權(quán)完成后,將 token 發(fā)送給主進程,下次前臺查詢時先在主進程獲取授權(quán)信息
- 通過統(tǒng)一的外部 redis 存取
兩種方法看來還是第二種好的不要太多,因此多進程的環(huán)境下,應(yīng)該使用外部數(shù)據(jù)庫統(tǒng)一存儲 token 信息
進一步的子進程間通信思考
雖然 node 中并沒有直接提供的進程間通訊功能,但是我們可以通過主進程相互協(xié)調(diào)進程間的通訊功能,需要定義標(biāo)準(zhǔn)的通信格式,例如
interface cmd { type: string from: number to: number msg: any }
這樣通過統(tǒng)一的格式,主進程就可以識別來自各個進程間的通信,起到進程通信中樞的功能
egg.js 中 agent 的實現(xiàn)
+--------+ +-------+ | Master |<-------->| Agent | +--------+ +-------+ ^ ^ ^ / | \ / | \ / | \ v v v +----------+ +----------+ +----------+ | Worker 1 | | Worker 2 | | Worker 3 | +----------+ +----------+ +----------+
我們看到 egg 在多進程模型之間實現(xiàn)了一個 agent 進程,這個進程主要負(fù)責(zé)對整個系統(tǒng)的定期維護
說到這里,Node.js 多進程方案貌似已經(jīng)成型,這也是我們早期線上使用的方案。但后來我們發(fā)現(xiàn)有些工作其實不需要每個 Worker 都去做,如果都做,一來是浪費資源,更重要的是可能會導(dǎo)致多進程間資源訪問沖突。舉個例子:生產(chǎn)環(huán)境的日志文件我們一般會按照日期進行歸檔,在單進程模型下這再簡單不過了:
每天凌晨 0 點,將當(dāng)前日志文件按照日期進行重命名
銷毀以前的文件句柄,并創(chuàng)建新的日志文件繼續(xù)寫入
試想如果現(xiàn)在是 4 個進程來做同樣的事情,是不是就亂套了。所以,對于這一類后臺運行的邏輯,我們希望將它們放到一個單獨的進程上去執(zhí)行,這個進程就叫 Agent Worker,簡稱 Agent。Agent 好比是 Master 給其他 Worker 請的一個『秘書』,它不對外提供服務(wù),只給 App Worker 打工,專門處理一些公共事務(wù)。
這樣我們可以指定一個進程作為 agent 進程,用于實現(xiàn)自己定義的事務(wù)。在 egg 中,主線程啟動后 首先 fork agent進程,當(dāng) agent 進程啟動完成后再啟動具體的 worker 進程。參照上面的代碼,相信這部分邏輯現(xiàn)在也不難實現(xiàn)了。這樣 agent 就會獲得 id 為1的進程
最后
P.S 勘誤,圖2中的線程應(yīng)該為進程,獨立的nodejs進程
本文相關(guān)代碼在 github
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
一次NodeJS內(nèi)存泄漏排查的實戰(zhàn)記錄
這篇文章主要給大家介紹了一次NodeJS內(nèi)存泄漏排查的實戰(zhàn)記錄,文中給出了詳細的排查過程以及內(nèi)存泄漏的解決方法,大家可以學(xué)習(xí)一下以備不時之需,需要的朋友可以參考下2022-03-03node.js利用redis數(shù)據(jù)庫緩存數(shù)據(jù)的方法
Redis數(shù)據(jù)庫采用極簡的設(shè)計思想,最新版的源碼包還不到2Mb。其在使用上也有別于一般的數(shù)據(jù)庫。下面這篇文章就來給大家介紹了node.js利用redis數(shù)據(jù)庫緩存數(shù)據(jù)的方法,需要的朋友可以參考借鑒,下面來一起看看吧。2017-03-03Node.js中的HTTP?Server對象與GET、POST請求
這篇文章介紹了Node.js中的HTTP?Server對象與GET、POST請求,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07用node開發(fā)并發(fā)布一個cli工具的方法步驟
這篇文章主要介紹了用node開發(fā)并發(fā)布一個cli工具的方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01