node项目架构与优化
為什么要用node
1、前后端耦合太緊密,中間加一層node,還要給前端裝一些亂七八糟的東西? java啥的服務(wù)環(huán)境。還有后臺(tái)返回接口的時(shí)候不管前端需不需要那些接口一起返回,其實(shí)只用到1~2 條數(shù)據(jù)。本來(lái)ajax就非常消耗時(shí)的事,就用其中一條,用node做一層中間層處理把沒(méi)用的接口剔除掉。
2、比如:一個(gè)10天項(xiàng)目,后臺(tái)開(kāi)發(fā)6天,前臺(tái)2天,測(cè)試2天。后臺(tái)開(kāi)發(fā)時(shí),沒(méi)有接口,前端得等著后臺(tái)的接口,如果后臺(tái)某種情況推遲了一天,前端就1天開(kāi)發(fā),測(cè)試要2天,肯定前端開(kāi)發(fā)不完。使用node我們可以并行開(kāi)發(fā),提高開(kāi)發(fā)效率。
3、proxy 代理層? ? java->node? ? 前端->node? 這種情況叫BFF,后臺(tái)是沒(méi)有跨域的。做了一層中間代理,可以自己控制路由,前端請(qǐng)求發(fā)給node,就不會(huì)出現(xiàn)跨域的問(wèn)題。node socket io 實(shí)時(shí)通訊。
4、node容錯(cuò),性能難做。
node異步IO原理淺析及優(yōu)化方案
-
異步IO的是與非
前端通過(guò)異步IO可以消除UI阻塞。
假設(shè)請(qǐng)求資源A的時(shí)間為M,請(qǐng)求資源B的時(shí)間為N,那么同步的請(qǐng)求耗時(shí)就為M+N,如果采用異步的方式占用時(shí)間為MAX(M,N)。
隨著業(yè)務(wù)的復(fù)雜,會(huì)引入分布式系統(tǒng),時(shí)間會(huì)線性的增加M+N+...和MAX(M,N,...),這會(huì)放大同步和異步之間的差異。
I/O是昂貴的,分布式I/O是更昂貴的。
一些底層知識(shí)
1、
CPU是鐘周期:1/CPU主頻->1s/3.1GHz
一級(jí)CPU是鐘周期:3.5GHz? ?1/3.5*3? io時(shí)間
2、
p是并行系統(tǒng)鐘的處理器數(shù)量;
f=ws/w為串行部分的比例;
我們分布到其他機(jī)器里,每個(gè)機(jī)器都用同樣的代碼。網(wǎng)絡(luò)要請(qǐng)求這文件,就比較慢 整個(gè)時(shí)間就比較長(zhǎng)。
并不是所有的所有并行的好,也并不少所有串行就好,分情況。系統(tǒng)會(huì)自動(dòng)根據(jù)情況來(lái)判斷使用并行還是串行。
3、操作系統(tǒng)對(duì)計(jì)算機(jī)進(jìn)行來(lái)抽象,將所有輸入輸出設(shè)備抽象為文件。內(nèi)核在進(jìn)行文件I/O操作時(shí),通過(guò)文件描述符進(jìn)行管理。應(yīng)用程序如果需要進(jìn)行I/O需要打開(kāi)文件描述符,在進(jìn)行文件和數(shù)據(jù)的讀寫(xiě)。異步IO不帶數(shù)據(jù)直接返回,要獲取數(shù)據(jù)還需要通過(guò)文件描述符再次讀取。
?
NodeJS使用與IO密集型不適用于CPU密集型
比如銀行,每次計(jì)算價(jià)格,java是多線程可以處理多個(gè)任務(wù),而Nodejs是單線程用異步不停的寫(xiě),寫(xiě)發(fā)上也非常復(fù)雜。可以有框架處理單線程問(wèn)題,但是性能上還是不如java。
-
Node對(duì)異步IO實(shí)現(xiàn)
完美的異步IO應(yīng)該是應(yīng)用程序發(fā)起阻塞調(diào)用,無(wú)需通過(guò)便利或者事件幻想等方式輪詢。
前端的event loop跟node event loop不一樣,前端比node event loop還要復(fù)雜一些。node程序進(jìn)來(lái)不停的轉(zhuǎn),就等于我們把米放到電飯煲里,定好時(shí)間,我們?nèi)ッe的,等他做好之后,會(huì)提示,已經(jīng)做好了。
-
幾個(gè)特殊對(duì)API
1、setTimeout和setInterval線程池不參與
2、process.nextTick()實(shí)現(xiàn)類(lèi)似setTimeout(function(){},0);每次調(diào)用放入隊(duì)列中,在下一輪循環(huán)中取出。
3、setImmediate();比provess.nextTick()優(yōu)先級(jí)低
4、Node如何實(shí)現(xiàn)一個(gè)Sleep?
async function test(){console.log('hello');await seelp(1000);console.log('word'); } function seelp(time){return new Promise(resolve=>setTimeout(resolve,time)) } test()
?
-
函數(shù)式編程在Node中對(duì)應(yīng)用
1、高階函數(shù):可以將函數(shù)作為輸入或者返回值,形成一種后續(xù)傳遞風(fēng)格的結(jié)果接受方式,而非單一的返回值形成。后續(xù)傳遞風(fēng)格的程序?qū)⒑瘮?shù)業(yè)務(wù)重點(diǎn)從返回值傳遞到回調(diào)函數(shù)中。
app.use(function(){//todo }) var emitter = new event.eventEmitter; emitter.on(function(){//todo })2、偏函數(shù):指定部分參數(shù)產(chǎn)生一個(gè)新的定制函數(shù)的形式就是偏函數(shù)。node中異步編程非常常見(jiàn),我們通過(guò)哨兵變量會(huì)很容易造成業(yè)務(wù)的混亂。underscore,after變量。
-
常用的Node控制異步API的技術(shù)手段
1、step、wind(提供等待的異步庫(kù))、bigpipe、Q.js
2、Async、Await
3、Promise/Defferred是一種先執(zhí)行異步調(diào)用,延遲傳遞的處理方式。Promise是高級(jí)接口,事件是低級(jí)接口。低級(jí)接口可以構(gòu)建更多復(fù)雜的場(chǎng)景,高級(jí)接口一旦定義,不太容易變化,不再有低級(jí)接口的靈活性,但對(duì)于解決問(wèn)題非常有效。
4、由于Node基于V8的原因,目前還不支持協(xié)程。協(xié)程不是進(jìn)程或線程,其執(zhí)行過(guò)程更類(lèi)似于子例程,或者說(shuō)不帶返回值的函數(shù)調(diào)用。
一個(gè)程序可以包含多個(gè)協(xié)程,可以對(duì)比一個(gè)進(jìn)程包含多個(gè)線程。來(lái)比較協(xié)程和線程。我們知道多個(gè)線程相對(duì)獨(dú)立,有自己的上下文,切換受系統(tǒng)控制;而協(xié)程也相對(duì)獨(dú)立,有自己的上下文,但是其切換由自己控制,由當(dāng)前協(xié)程切換到其他協(xié)程有當(dāng)前協(xié)程來(lái)控制。
內(nèi)存管理與優(yōu)化
?V8垃圾回收機(jī)制
node使用javascript在服務(wù)端操作大內(nèi)存對(duì)象受到了一定的限制,64位系統(tǒng)下約為1.4GB,32位系統(tǒng)是0.7GB
process.memoryUsage->rss、heaptTotal、heapUsed
V8的垃圾回收策略主要基于分代式垃圾回收機(jī)制。在自動(dòng)垃圾回收的演變過(guò)程中,人們發(fā)現(xiàn)沒(méi)有一種垃圾回收算法能夠勝任所有場(chǎng)景。V8內(nèi)存分為新生代和老生代。新生代為存活時(shí)間較短對(duì)象,老圣代為存活時(shí)間較長(zhǎng)的對(duì)象。
Scavenge算法
在分帶基礎(chǔ)上,新生代的對(duì)象主要通過(guò)Scavenge算法進(jìn)行垃圾回收,在具體實(shí)現(xiàn)時(shí)主要采用cheney算法,cheney算法是一種采用復(fù)制的方法實(shí)現(xiàn)的垃圾回收算法。它將內(nèi)存一分為二,每一個(gè)空間稱(chēng)為semispace。這兩個(gè)semispace中一個(gè)處于使用,一個(gè)處于閑置。處于使用的稱(chēng)之為From,檢查From存活對(duì)象復(fù)制到To。非存活被釋放。然后互換位置。再次進(jìn)行回收,發(fā)現(xiàn)被回收過(guò)直接晉升,或者發(fā)現(xiàn)To空間已經(jīng)使用來(lái)超過(guò)25%。他的缺點(diǎn)只能使用堆內(nèi)存的一半,這是一個(gè)典型的空間換時(shí)間的辦法,但是新生代生命周期較短,恰恰就適合這個(gè)算法。
老生代空間生成完成肯定要有東西管理它,就有來(lái)mark-sweep和mark-compact
V8老生代主要采用mark-sweep和mark-compact,在使用Scavenge不合適。一個(gè)是對(duì)象較多需要賦值量太大而且還是沒(méi)能解決空間問(wèn)題。Mark-Sweep是標(biāo)記清除,標(biāo)記那些死亡的對(duì)象,然后清除。但是清除過(guò)后出現(xiàn)內(nèi)存不連續(xù)的情況,所有我們要使用Mark-Compact,他是基于mark-sweep演變而來(lái)的,它現(xiàn)將活著的對(duì)象移到一邊,移動(dòng)完成后,直接清理邊界外的內(nèi)存。當(dāng)CPU空間不足的時(shí)候會(huì)非常高效。V8還引入來(lái)延遲處理,增量處理,并計(jì)劃引入并標(biāo)記處理。
常見(jiàn)的內(nèi)存泄漏問(wèn)題
1、無(wú)限制增長(zhǎng)的數(shù)組
2、無(wú)限制設(shè)置屬性和值
3、任何模塊內(nèi)的私有變量和方法均是永駐內(nèi)存的a=null
4、大循環(huán),無(wú)GC(垃圾回收機(jī)制)機(jī)會(huì)
內(nèi)存泄漏分析
node-inspector
console.log("Server PID",process.pid);
sodu node --inspect app.js
whie true;do curl "http:localhost:1337/";done
top -pid 2322
大規(guī)模Node站點(diǎn)結(jié)構(gòu)原理分析
經(jīng)典的MVC框架
model-view-Controller
javaweb多層架構(gòu)
node 集群應(yīng)用
? 預(yù)備上線
1、前端工程化的搭載動(dòng)態(tài)文件的MAP分析壓縮打包合并至CDN
2、單側(cè)、壓力測(cè)試、性能分析工具發(fā)現(xiàn)Bug
3、編寫(xiě)nginx-conf實(shí)現(xiàn)負(fù)載均衡和反向代理
4、PM2啟動(dòng)應(yīng)用生序小流量灰度上線,修復(fù)Bug
5、上線前的不眠夜、你見(jiàn)過(guò)凌晨5點(diǎn)的北京么?
多線程
1、master進(jìn)程均為主進(jìn)程,Fork可以創(chuàng)造主進(jìn)程。
2、通過(guò)child_process可以和NET模塊組合,可以創(chuàng)建多個(gè)線程并監(jiān)聽(tīng)統(tǒng)一端口。通過(guò)句柄傳遞完成自動(dòng)啟動(dòng)、發(fā)射自殺信號(hào)、限量重啟、負(fù)載均衡。
3、node默認(rèn)的機(jī)制是采用操作系統(tǒng)的搶占式策略。閑著的進(jìn)程爭(zhēng)搶任務(wù),但是會(huì)造成CPU閑置的IO暫時(shí)并未閑置。Node后來(lái)引入來(lái)Round-Robin機(jī)制,也叫輪詢調(diào)度。主進(jìn)程接受任務(wù),在發(fā)。
4、每個(gè)子進(jìn)程做好自己的事,然后通過(guò)進(jìn)程間通信來(lái)將他們鏈接起來(lái)。這符合Unix的設(shè)計(jì)理念,每個(gè)進(jìn)程只做一件事,并做好。將福啊分解為簡(jiǎn)單,將簡(jiǎn)單組合程強(qiáng)大。
PM2
pm2是一個(gè)自帶負(fù)載均衡功能的node應(yīng)用的進(jìn)程管理器。
當(dāng)你要把你的獨(dú)立代碼利用全部的服務(wù)器上的所有CPU,并保證進(jìn)程永遠(yuǎn)活著,0秒重載。
1、內(nèi)建負(fù)載均衡(使用node cluster集群模塊)
2、后臺(tái)運(yùn)行
3、0秒停機(jī)重仔
4、具有Ubuntu和CentOS的啟動(dòng)腳本
5、停止不穩(wěn)定的進(jìn)程(避免無(wú)限循環(huán))
6、控制臺(tái)檢測(cè)
7、提供HTTP API
8、遠(yuǎn)程控制和實(shí)時(shí)的接口API(Nodejs 模塊,允許和PM2進(jìn)程管理交互)
測(cè)試過(guò)Nodejs v0.11 v0.10 v0.8版本,兼容CoffeeScript,基于linux和MacOs
我之前是前端連java感覺(jué)還可以,如果我中間加一層node,是不是就變慢了呢,并不是,首先java跟node在同樣一個(gè)機(jī)房他倆請(qǐng)求的時(shí)間被嚴(yán)格限制在1ms(毫秒),甚至一些團(tuán)隊(duì)100ms已經(jīng)頂天了,300ms服務(wù)肯定有問(wèn)題。用戶肯定無(wú)法感知的,node和java走了一次http,會(huì)有3次握手,即使是毫秒也是一次浪費(fèi),node和java 走的是Linux Virtual Server(Linux虛擬服務(wù)器)通信。
?
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/139199228-haicao/p/9193753.html
總結(jié)
以上是生活随笔為你收集整理的node项目架构与优化的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 区块链100讲:据说,80%的人都搞不懂
- 下一篇: 机器学习:数据预处理之独热编码(One-