摘要:一般由客戶端發(fā)送,用來(lái)表示報(bào)文段中第一個(gè)數(shù)據(jù)字節(jié)在數(shù)據(jù)流中的序號(hào),主要用來(lái)解決網(wǎng)絡(luò)包亂序的問(wèn)題。為有效,為無(wú)效表示,當(dāng)數(shù)據(jù)包得到后,立馬給應(yīng)用程序使用到最頂端用來(lái)確保連接的安全。親,那進(jìn)程和線程區(qū)別是什么嘞這算是計(jì)算機(jī)的基本知識(shí)吧。
在正文之前,我想問(wèn)大家一個(gè)問(wèn)題:
問(wèn):親,你有基礎(chǔ)嗎?
答: 有啊,你說(shuō)前端嗎? 不就是HTML,JS,CSS 嗎? so easy~
問(wèn): oh-my-zsh... 好吧,那問(wèn)題來(lái)了,挖掘機(jī)技術(shù)哪家強(qiáng)... 開(kāi)玩笑。
現(xiàn)在才是問(wèn)題的正內(nèi)容。
你知道TCP的基本內(nèi)容嗎?(母雞啊~)
好吧,那你知道TCP的3次握手,4次揮手嗎?(知道一點(diǎn)點(diǎn))
恩,好,那什么是進(jìn)程呢?什么是線程呢?(母雞啊。。)
那并發(fā)和并行又是什么呢?(母雞啊)
OMG, 那nodeJS多進(jìn)程實(shí)現(xiàn)你會(huì)嗎?(不會(huì)呀~~~ md ...這都是些shenmegui)
其實(shí),說(shuō)多了都是淚,這些都是程序員的基本素質(zhì)呀。。。 面tencent的時(shí)候,被一個(gè)總監(jiān),罵的阿彌陀佛么么噠. 今天在這里和大家分享一下,我的血淚史。
TCP內(nèi)容工欲善其事,必先利其器
一個(gè)程序員境界的提升,并不在于你寫(xiě)的一首好代碼,更在于你能說(shuō)出代碼背后的故事。ok~ 雞湯灌完了。我們開(kāi)始說(shuō)方法了。
首先這幅圖大家必須記得非常清楚才行。
對(duì)了還有,
OSI七層模型大家應(yīng)該爛熟于心的。
其中TCP處理transport層,主要是用來(lái)建立可靠的連接。 而建立連接的基礎(chǔ),是他豐富的報(bào)文內(nèi)容(md~超級(jí)多).我們先來(lái)解釋一下。 首先,我們TCP3次握手用的報(bào)文就是綠色的"TCP Flags"內(nèi)容。 通過(guò)發(fā)送ACK,SYN包實(shí)現(xiàn)。具體涉及的Tag詳見(jiàn):
Source Port / Destination Port:這個(gè)就是客戶端口(源端口)和服務(wù)器端口(目的端口). 端口就是用來(lái)區(qū)別主機(jī)中的不同進(jìn)程,通過(guò)結(jié)合源IP和目的IP結(jié)合,得出唯一的TCP連接。
Sequence Number(seqNumber): 一般由 客戶端發(fā)送,用來(lái)表示報(bào)文段中第一個(gè)數(shù)據(jù)字節(jié)在數(shù)據(jù)流中的序號(hào),主要用來(lái)解決網(wǎng)絡(luò)包亂序的問(wèn)題。
Acknowledgment Number(ACK): 即就是用來(lái)存放客戶端發(fā)來(lái)的seqNumber的下一個(gè)信號(hào)(seqNumber+1). 只有當(dāng) TCP flags中的ACK為1時(shí)才有效. 主要是用來(lái)解決不丟包的問(wèn)題。
TCP flags: TCP中有6個(gè)首部,用來(lái)控制TCP連接的狀態(tài).取值為0,1.這6個(gè)有:URG,ACK,PSH,RST,SYN,F(xiàn)IN.
URG 當(dāng)為1時(shí),用來(lái)保證TCP連接不被中斷, 并且將該次TCP內(nèi)容數(shù)據(jù)的緊急程度提升(就是告訴電腦,你丫趕快把這個(gè)給resolve了)
ACK 通常是服務(wù)器端返回的。 用來(lái)表示應(yīng)答是否有效。 1為有效,0為無(wú)效
PSH 表示,當(dāng)數(shù)據(jù)包得到后,立馬給應(yīng)用程序使用(PUSH到最頂端)
RST 用來(lái)確保TCP連接的安全。 該flag用來(lái)表示 一個(gè)連接復(fù)位的請(qǐng)求。 如果發(fā)生錯(cuò)誤連接,則reset一次,重新連。當(dāng)然也可以用來(lái)拒絕非法數(shù)據(jù)包。
SYN 同步的意思,通常是由客戶端發(fā)送,用來(lái)建立連接的。第一次握手時(shí): SYN:1 , ACK:0. 第二次握手時(shí): SYN:1 ACK:1
FIN 用來(lái)表示是否結(jié)束該次TCP連接。 通常當(dāng)你的數(shù)據(jù)發(fā)送完后,會(huì)自動(dòng)帶上FIN 然后斷開(kāi)連接
恩,基本的TCP內(nèi)容,大家應(yīng)該掌握了吧。OK, go on.
What"s TCP 3次握手還是一樣, 先上張圖,讓大家先看一下。 上面大家已經(jīng)基本了解了TCP里面相應(yīng)的字段,現(xiàn)在看看圖里面的是不是覺(jué)得有些親切嘞?
其實(shí),大家看上面的圖,差不多都已經(jīng)能夠摸清楚,每次發(fā)送請(qǐng)求的內(nèi)容。其實(shí),TCP3次握手是為了建立 穩(wěn)定可靠的連接。所以也就不存在神馬 2次連接等的怪癖。
(圖中flag說(shuō)明:SYN包表示標(biāo)志位syn=1,ACK包表示標(biāo)志位ack=1,SYN+ACK包表示標(biāo)志位syn=1,ack=1)
現(xiàn)在,我們來(lái)正式進(jìn)入3次握手環(huán)節(jié)。
第一次握手. 客戶端向服務(wù)器發(fā)送一個(gè)SYN包,并且添加上seqNumber(假設(shè)為x),然后進(jìn)入SYN_SEND狀態(tài),并且等待服務(wù)器的確認(rèn)。
第二次握手: 服務(wù)器接受SYN包,并且進(jìn)行確認(rèn),如果該請(qǐng)求有效,則將TCP flags中的ACK 標(biāo)志位置1, 然后將AckNumber置為(seqNumber+1),并且再添加上自己的seqNumber(y), 完成后,返回給客戶端.服務(wù)器進(jìn)入SYN_RECV狀態(tài).(這里服務(wù)端是發(fā)送SYN+ACK包)
第三次握手 客戶端接受ACK+SYN報(bào)文后,獲取到服務(wù)器發(fā)送seqNumber(y), 并且 將新頭部的AckNumber變?yōu)?y+1).然后發(fā)送給服務(wù)器,完成TCP3次連接。此時(shí)服務(wù)器和客戶端都進(jìn)入ESTABLISHED狀態(tài).
回答一下這個(gè)比較尷尬的問(wèn)題,為什么只有3次握手,而不是4次,或者2次?
很簡(jiǎn)單呀,因?yàn)?次就夠了,干嘛用4次。23333. 舉個(gè)例子吧,假如是2次的話, 可能會(huì)出現(xiàn)這樣一個(gè)情況。
當(dāng)客戶端發(fā)送一次請(qǐng)求A后,但是A在網(wǎng)絡(luò)延遲了很久, 接著客戶端又發(fā)送了一次B,但是此時(shí)A已經(jīng)無(wú)效了。 接著服務(wù)器相應(yīng)了B,并返回TCP連接頭,建立連接(這里就2次哈)。 然后,A 歷經(jīng)千山萬(wàn)水終于到服務(wù)器了, 服務(wù)器一看有請(qǐng)求來(lái)了,則接受,由于一開(kāi)始A帶著的TCP格式都是正確的,那么服務(wù)器,理所應(yīng)當(dāng)?shù)囊卜祷爻晒B接的flag,但是,此時(shí)客戶端已經(jīng)判斷該次請(qǐng)求無(wú)效,廢棄了。 然后服務(wù)器,就這么一直掛著(浪費(fèi)資源),造成的一個(gè)問(wèn)題是,md, 這個(gè)鍋是誰(shuí)的? 所以,為了保險(xiǎn)起見(jiàn),再補(bǔ)充一次連接就可以了。所以3次是最合適的。在Chinese中,以3為起稱為多,如果你用4,5,6,7,8...次的話,這不更浪費(fèi)嗎?
TCP4次揮手TCP4次揮手,是比較簡(jiǎn)單的。大家對(duì)照上面那個(gè)圖,我們一步一步進(jìn)行一下講解。
第一次揮手: A機(jī)感覺(jué)此時(shí)如果keep-alive比較浪費(fèi)資源,則他提出了分手的請(qǐng)求。設(shè)置SeqNumber和AckNumber之后,向B機(jī)發(fā)送FIN包, 表示我這已經(jīng)沒(méi)有數(shù)據(jù)給你了。然后A機(jī)進(jìn)入FIN_WAIT_1狀態(tài)
第二次揮手:B機(jī)收到了A機(jī)的FIN包,已經(jīng)知道了A機(jī)沒(méi)有數(shù)據(jù)再發(fā)送了。此時(shí)B機(jī)會(huì)給A機(jī)發(fā)送一個(gè)ACK包,并且將AckNumber 變?yōu)?A機(jī)傳輸來(lái)的SeqNumber+1. 當(dāng)A機(jī)接受到之后,則變?yōu)镕IN_WAIT_2狀態(tài)。表示已經(jīng)得到B機(jī)的許可,可以進(jìn)行關(guān)閉操作。不過(guò)此時(shí),B機(jī)還是可以向A機(jī)發(fā)送請(qǐng)求的。
第三次揮手 B機(jī)向A機(jī)發(fā)送FIN包,請(qǐng)求關(guān)閉,相當(dāng)于告訴A機(jī),我這里也沒(méi)有你要的數(shù)據(jù)了。然后B機(jī)進(jìn)入CLOSE_WAIT狀態(tài).(這里還需要帶上SeqNumber,大家看圖說(shuō)話就可以了)
第四次揮手 A機(jī)接收到B機(jī)的FIN包之后,然后同樣,發(fā)送一個(gè)ACK包給B機(jī)。 B機(jī)接受到之后,就斷開(kāi)了。 而A機(jī) 會(huì)等待2MSL之后,如果沒(méi)有回復(fù),確保服務(wù)器端確實(shí)是關(guān)閉了。然后A機(jī)也可以關(guān)閉連接。A,B都進(jìn)入了CLOSE狀態(tài).
明白了嗎?
大哥~ 等等,什么是2MSL呀~
哦,對(duì)哦。 這個(gè)還么說(shuō)...
2MSL=2*MSL. 而MSL其實(shí)就是Maximum Segment Lifetime,中文意思就是報(bào)文最大生存時(shí)間。RFC 793中規(guī)定MSL為2分鐘,實(shí)際應(yīng)用中常用的是30秒,1分鐘和2分鐘等。 同樣上面的TIME_WAT狀態(tài)其實(shí)也就是2MSL狀態(tài)。 如果超過(guò)改時(shí)間,則會(huì)將該報(bào)文廢棄,然后直接進(jìn)入CLOSED狀態(tài).
親,請(qǐng)問(wèn)php是一門什么語(yǔ)言? (提示,關(guān)于進(jìn)程)
官方回答: php是一門基于多線程的語(yǔ)言
親,請(qǐng)問(wèn)nodeJS是一門什么語(yǔ)言?(提示,關(guān)于線程)
官方回答: Node.js是單線程!異步!非阻塞!(不過(guò)早已可以實(shí)現(xiàn)多進(jìn)程交互了)
那php和nodeJS區(qū)別在哪呢?具體可以見(jiàn)圖:
PHP
NodeJS
ok~ 簡(jiǎn)單吧。
親,那進(jìn)程和線程區(qū)別是什么嘞?
go die /(ㄒoㄒ)/~~
這算是計(jì)算機(jī)的基本知識(shí)吧。 首先我們需要記住的是,進(jìn)程包括線程。這非常重要。
進(jìn)程就是系統(tǒng)分配資源的基本單位(比如CPU,內(nèi)存等)
線程就是程序執(zhí)行的最小單位
進(jìn)程有自己的空間,如果一個(gè)進(jìn)程崩潰不會(huì)引起其它進(jìn)程的崩潰。
線程,沒(méi)有自己獨(dú)立的空間,多個(gè)線程共享的是進(jìn)程的地址空間,當(dāng)然處理一些基本的如程序計(jì)數(shù)器,一組寄存器和棧等。
如果一個(gè)線程崩潰,它所在的進(jìn)程就崩潰了。 雖然說(shuō),多進(jìn)程很穩(wěn)定,但是進(jìn)程切換時(shí),耗費(fèi)的資源也是很大的。 所以對(duì)于大并發(fā)的nodeJS來(lái)說(shuō),使用多線程的效果要遠(yuǎn)遠(yuǎn)比多進(jìn)程快,穩(wěn)定。
1.系統(tǒng)在啟動(dòng)一個(gè)進(jìn)程的時(shí)候,會(huì)首先在資源中獨(dú)立一塊出來(lái),在后臺(tái)建立一些列表進(jìn)行維護(hù)。 而,線程是比進(jìn)程低一個(gè)level的,所以創(chuàng)建線程所耗費(fèi)的資源要遠(yuǎn)遠(yuǎn)比,創(chuàng)建進(jìn)程的資源少。
由于進(jìn)程本身就比較復(fù)雜,所以如果進(jìn)行進(jìn)程切換的話,造成的性能損耗也是不言而喻的(因?yàn)槎鄠€(gè)進(jìn)程獨(dú)立,在切換的時(shí)候還需要保證各自的獨(dú)立性)。 而線程切換就不同了,因?yàn)樵谔幵谕贿M(jìn)程下面,對(duì)于其他的進(jìn)程都是透明化的(內(nèi)存共享),所以在進(jìn)行進(jìn)程切換時(shí),所耗費(fèi)的資源遠(yuǎn)遠(yuǎn)比進(jìn)程切換的小。
在Linux和window下,CPU的分配是根據(jù)線程數(shù)來(lái)的,如果
總線程數(shù)<= CPU數(shù)量:并行運(yùn)行 總線程數(shù)> CPU數(shù)量:并發(fā)運(yùn)行
并行指的是,當(dāng)你的CPU核數(shù)比線程數(shù)多的話,則會(huì)將每個(gè)線程都分在一個(gè)CPU核里進(jìn)行處理。
并發(fā)指的是,當(dāng)你的CPU核數(shù)比線程數(shù)少的話,則會(huì)利用“時(shí)間片輪轉(zhuǎn)進(jìn)程調(diào)度算法”,對(duì)每個(gè)線程進(jìn)行同等的運(yùn)行。
4.細(xì)化進(jìn)程的處理,通常一個(gè)進(jìn)程可以拆分為多個(gè)線程進(jìn)行處理,就和模塊化處理是類似的,使用模塊化書(shū)寫(xiě)的效果要遠(yuǎn)遠(yuǎn)比使用單main入口方式書(shū)寫(xiě) 清晰,穩(wěn)定。
并發(fā),并行原理親, 并發(fā)和并行有什么共同點(diǎn)嗎?
恩~ 有的, 他們都有個(gè)‘并’子,字面上看起來(lái)都是同時(shí)執(zhí)行的意思。
沒(méi)錯(cuò),當(dāng)然只是字面上而已。
實(shí)際上,并發(fā)和并行是完全不同的概念。 這里主要和CPU核數(shù)有關(guān)。這里為了理解,拿線程來(lái)作為參考吧。
當(dāng)你的
總線程數(shù)<= CPU數(shù)量:并行運(yùn)行 總線程數(shù)> CPU數(shù)量:并發(fā)運(yùn)行
很明顯,并行其實(shí)是真正意義上的同時(shí)執(zhí)行。 當(dāng)線程數(shù)< CPU核數(shù)時(shí),每個(gè)線程會(huì)獨(dú)立分配到一個(gè)CPU里進(jìn)行處理。
大家看過(guò)火影忍者嗎?
沒(méi)錯(cuò),就是鳴人 出關(guān) 口遁九尾之后。 他使用影分身,跑去各地支援同伴,對(duì)抗斑。 這里類比來(lái)說(shuō),就可以理解為, 每個(gè)CPU 都是鳴人的一個(gè)影分身,他們執(zhí)行這各自不同的工作,但是,在同一時(shí)間上,他們都在運(yùn)行。 這就是并行。
那并發(fā)嘞?
其實(shí),并發(fā)有點(diǎn)難以理解,他做的工作其實(shí),就是利用一系列算法實(shí)現(xiàn),并行做的事。一個(gè)比較容易理解的就是“時(shí)間片輪轉(zhuǎn)進(jìn)程調(diào)度算法”。
即: 在系統(tǒng)控制下,每個(gè)線程輪流使用CPU,而且,每個(gè)線程使用時(shí)間必須很短(比如10ms), 所以這樣切換下來(lái)。我們(愚蠢的人類,哈哈哈), 天真的以為任務(wù),真的是在"并行"執(zhí)行.
一開(kāi)始nodeJS最令人詬病的就是他的單線程特性。既是絕招也是死穴,不過(guò)nodeJS發(fā)展很快,在v0.8版本就已經(jīng)添加了cluster作為內(nèi)置模塊,實(shí)現(xiàn)多核的利用。
關(guān)于nodeJS的進(jìn)程模塊,最主要的當(dāng)然還是cluster. 通過(guò)調(diào)用child_process.fork()函數(shù)來(lái)開(kāi)啟進(jìn)程。 先看一個(gè)具體的demo(from 官網(wǎng))
var cluster = require("cluster"); var http = require("http"); var numCPUs = require("os").cpus().length; if (cluster.isMaster) { console.log("master start..."); // Fork workers. for (var i = 0; i < numCPUs; i++) { cluster.fork(); } //用來(lái)監(jiān)聽(tīng)子worker創(chuàng)建監(jiān)聽(tīng)服務(wù) cluster.on("listening",function(worker,address){ console.log("listening: worker " + worker.process.pid +", Address: "+address.address+":"+address.port); }); cluster.on("exit", function(worker, code, signal) { console.log("worker " + worker.process.pid + " died"); }); } else { http.createServer(function(req, res) { res.writeHead(200); res.end("hello world "); }).listen(0); }
存放為app.js 然后運(yùn)行node app.js就可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的多進(jìn)程效果。
結(jié)果可能為下:
master start... listening: worker 1559, Address: null:57803 listening: worker 1556, Address: null:57803 listening: worker 1558, Address: null:57803 listening: worker 1557, Address: null:57803
可以從上面的demo中看出,通過(guò)cluster.isMaster來(lái)區(qū)分master和worker. 而master和worker之間使用listen(0)進(jìn)行通信.
server.listen(0):在master和worker通信過(guò)程,集群中的worker會(huì)打開(kāi)一個(gè)隨機(jī)端口共用,通過(guò)socket通信像上例中的57803
當(dāng)然你也可以手動(dòng)打開(kāi)一個(gè)端口共享監(jiān)聽(tīng)。像這樣.
http.createServer(function(req, res) { res.writeHead(200); res.end("hello world "); }).listen(3000);cluster對(duì)應(yīng)API
cluster對(duì)象的屬性和函數(shù)
cluster.setttings:配置集群參數(shù)對(duì)象
cluster.isMaster:判斷是不是master節(jié)點(diǎn)*
cluster.isWorker:判斷是不是worker節(jié)點(diǎn)*
Event: "fork": 監(jiān)聽(tīng)創(chuàng)建worker進(jìn)程事件
Event: "online": 監(jiān)聽(tīng)worker創(chuàng)建成功事件
Event: "listening": 監(jiān)聽(tīng)worker開(kāi)啟的http.listen
Event: "disconnect": 監(jiān)聽(tīng)worker斷線事件
Event: "exit": 監(jiān)聽(tīng)worker退出事件
Event: "setup": 監(jiān)聽(tīng)setupMaster事件
cluster.setupMaster([settings]): 設(shè)置集群參數(shù)
cluster.fork([env]): 創(chuàng)建worker進(jìn)程
cluster.disconnect([callback]): 關(guān)閉worket進(jìn)程*
cluster.worker: 獲得當(dāng)前的worker對(duì)象*
cluster.workers: 獲得集群中所有存活的worker對(duì)象*
通過(guò)cluster.worker獲得的worker對(duì)象和相應(yīng)的參數(shù)
worker.id: 進(jìn)程ID號(hào)
worker.process: ChildProcess對(duì)象*
worker.suicide: 在disconnect()后,判斷worker是否自殺*
worker.send(message, [sendHandle]):* master給worker發(fā)送消息。注:worker給發(fā)master發(fā)送消息要用process.send(message)
worker.kill([signal="SIGTERM"]): 殺死指定的worker,別名destory()*
worker.disconnect(): 斷開(kāi)worker連接,讓worker自殺
Event: "message": 監(jiān)聽(tīng)master和worker的message事件
Event: "online": 監(jiān)聽(tīng)指定的worker創(chuàng)建成功事件
Event: "listening": 監(jiān)聽(tīng)master向worker狀態(tài)事件
Event: "disconnect": 監(jiān)聽(tīng)worker斷線事件
Event: "exit": 監(jiān)聽(tīng)worker退出事件
這些就是cluster的全部?jī)?nèi)容。不過(guò)這僅僅只是內(nèi)容而已,如果使用cluster,這便是我們程序員要做的事了。
進(jìn)程通信由于nodeJS 只能實(shí)現(xiàn)單進(jìn)程的效果,所以他的進(jìn)程數(shù)只能為一個(gè),但是通過(guò)引用cluster模塊,可以開(kāi)啟多個(gè)子進(jìn)程實(shí)現(xiàn)CPU的利用。
簡(jiǎn)單進(jìn)程交互
運(yùn)行后的結(jié)果為:
[master] start master... [master] fork: worker1 [master] fork: worker2 [master] fork: worker3 [master] fork: worker4 [master] online: worker1 [master] online: worker4 [master] online: worker2 [master] online: worker3 [worker] start worker ...1 [worker] start worker ...4 [worker] start worker ...2 [master] listening: worker4,pid:990, Address:null:3000 [master] listening: worker1,pid:987, Address:null:3000 [master] listening: worker2,pid:988, Address:null:3000 [worker] start worker ...3 [master] listening: worker3,pid:989, Address:null:3000
參照注釋代碼和上述的結(jié)果,我們可以很容易的得到一個(gè)觸發(fā)邏輯。
運(yùn)行過(guò)程是:
首先f(wàn)ork子進(jìn)程
觸發(fā)fork事件
創(chuàng)建成功,觸發(fā)online事件
然后重新執(zhí)行一遍app.js,通過(guò)isWorker判斷子進(jìn)程
創(chuàng)建子進(jìn)程服務(wù)->觸發(fā)master上的listening
st=>start: 首先f(wàn)ork子進(jìn)程 op1=>operation: 觸發(fā)fork事件 op2=>operation: 創(chuàng)建成功,觸發(fā)online事件 op3=>operation: 然后重新執(zhí)行一遍app.js,通過(guò)isWorker判斷子進(jìn)程 op4=>operation: 創(chuàng)建子進(jìn)程服務(wù)->觸發(fā)master上的listening e=>end st->op1->op2->op3->op4->e
上面只是創(chuàng)建滿負(fù)載子進(jìn)程的流程。 但怎樣實(shí)現(xiàn)進(jìn)程間的交互呢? 很簡(jiǎn)單,master和worker監(jiān)聽(tīng)message事件,通過(guò)傳遞參數(shù),進(jìn)行交互。
cluster.worker.send(message[,handleFn]) master向worker發(fā)送信息
process.send(message[,handleFn]); worker向master發(fā)送信息
這個(gè)是多進(jìn)程之間的通信
communication
我們來(lái)分解一下代碼塊:
//開(kāi)啟master監(jiān)聽(tīng)worker的通信 cluster.workers[id].on("message", function(msg){ //... }); //開(kāi)啟worker監(jiān)聽(tīng)master的通信 process.on("message", function(msg) { //... });
運(yùn)行上面的demo. 這里就不細(xì)說(shuō),整個(gè)流程,只看一下信息通信這一塊了。
創(chuàng)建子進(jìn)程,觸發(fā)listening事件
使用process.on監(jiān)聽(tīng)message
接受master發(fā)送過(guò)來(lái)的消息
再向master返回消息
st=>start: 創(chuàng)建子進(jìn)程,觸發(fā)listening事件 op1=>operation: 使用process.on監(jiān)聽(tīng)message op2=>operation: 接受master發(fā)送過(guò)來(lái)的消息 op3=>operation: 再向master返回消息 op4=>operation: others e=>others st->op1->op2->op3->op4nodeJS負(fù)載均衡
現(xiàn)在,nodeJS負(fù)載均衡應(yīng)該是最容易實(shí)現(xiàn)的,其內(nèi)部已經(jīng)幫我們封裝好了,我們直接調(diào)用就over了。
其中,實(shí)現(xiàn)負(fù)載均衡的模塊就是cluster。以前cluster確實(shí)很累贅。負(fù)載均衡的算法實(shí)現(xiàn)的不是很好,導(dǎo)致的下場(chǎng)就是npm2的興起。不過(guò)現(xiàn)在已經(jīng)實(shí)現(xiàn)了負(fù)載均衡,官方說(shuō)法就是用round-robin,來(lái)進(jìn)行請(qǐng)求分配。 round-robin其實(shí)就是一個(gè)隊(duì)列的循環(huán),灰常容易理解。先看一下,cluster封裝好實(shí)現(xiàn)的負(fù)載均衡.
var cluster = require("cluster"); var http = require("http"); var numCPUs = require("os").cpus().length; if (cluster.isMaster) { console.log("[master] " + "start master..."); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on("listening", function (worker, address) { console.log("[master] " + "listening: worker" + worker.id + ",pid:" + worker.process.pid + ", Address:" + address.address + ":" + address.port); }); } else if (cluster.isWorker) { console.log("[worker] " + "start worker ..." + cluster.worker.id); var num = 0; http.createServer(function (req, res) { num++; console.log("worker"+cluster.worker.id+":"+num); res.end("worker"+cluster.worker.id+",PID:"+process.pid); }).listen(3000); }
(哥哥,你騙人,這哪里實(shí)現(xiàn)了負(fù)載均衡,這不就是上面的算法么?)
是呀,,, 我又沒(méi)說(shuō)負(fù)載均衡不是這個(gè)。
負(fù)載均衡就是幫你解決請(qǐng)求的分配問(wèn)題。ok~ 為了證明,我沒(méi)有騙你,我們來(lái)進(jìn)行測(cè)試一下。
使用brew安裝siege測(cè)試,當(dāng)然你也可以使用其他測(cè)試工具,不過(guò)在MAC 上面最好使用siege和webbench或者ab,我這里使用siege
brew install siege
使用的測(cè)試語(yǔ)法就是
siege -c 并發(fā)數(shù) -t 運(yùn)行測(cè)試時(shí)間 URL
測(cè)試的時(shí)間后面需要帶上單位,比如s,m,h,d等。默認(rèn)單位是m(分鐘). 舉個(gè)例子吧.
siege -c 100 -t 10s http://girls.hustonline.net
對(duì)女生節(jié)網(wǎng)頁(yè)進(jìn)行 100次并發(fā)測(cè)試,持續(xù)時(shí)間是10s.
當(dāng)然siege里還有其他的參數(shù).
-c NUM 設(shè)置并發(fā)的數(shù)量.eg: -c 100; //設(shè)置100次并發(fā)
-r NUM 設(shè)置發(fā)送幾輪的請(qǐng)求,即,總的請(qǐng)求數(shù)為: -cNum*-rNum但是, -r不能和-t一起使用(為什么呢?你猜).eg: -r 20
-t NUM 測(cè)試持續(xù)時(shí)間,指你運(yùn)行一次測(cè)試需要的時(shí)間,在timeout后,結(jié)束測(cè)試.
-f file. 用來(lái)測(cè)試file里面的url路徑.file的尾綴需要為.url. eg: -f girls.url.
-b . 就是詢問(wèn)開(kāi)不開(kāi)啟基準(zhǔn)測(cè)試(benchmark)。 這個(gè)參數(shù)不太重要,有興趣的同學(xué),可以下去學(xué)習(xí)一下。
siege常用的就是這幾個(gè). 通常我們是搭配 -c + -r 或者-c + -t.
OK,現(xiàn)在我們開(kāi)始我們的測(cè)試 procedure.
首先開(kāi)啟多進(jìn)程N(yùn)odeJS. node app.js
使用siege -c 100 -t 10s 127.0.0.1:3000. (Ps: 當(dāng)然也可以使用http://localhost:3000進(jìn)行代替)
得到的結(jié)果為
Transactions: 600 hits Availability: 100.00 % Elapsed time: 6.08 secs Data transferred: 0.01 MB Response time: 0.01 secs Transaction rate: 98.68 trans/sec Throughput: 0.00 MB/sec Concurrency: 0.88 Successful transactions: 600 Failed transactions: 0 Longest transaction: 0.04 Shortest transaction: 0.00
在10s內(nèi),發(fā)起了600次請(qǐng)求,最大的峰值是98.68 trans/sec。 通過(guò)統(tǒng)計(jì)分析,得到每個(gè)worker的分發(fā)量.
worker1:162 worker2:161 worker3:167 worker4:170
可以看出,基本上每個(gè)負(fù)載上分配的請(qǐng)求的數(shù)目都差不多。這就已經(jīng)達(dá)到了負(fù)載均衡的效果。
下一篇會(huì)對(duì)nodeJS已經(jīng)相關(guān)的測(cè)試工具做一些介紹哦。
盡請(qǐng)期待。
ending~
大家如果感興趣,給我一杯咖啡喝喝吧~
轉(zhuǎn)載請(qǐng)注明出處和作者
原文連接:https://segmentfault.com/a/1190000004569460
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/8733.html
摘要:前言月份開(kāi)始出沒(méi)社區(qū),現(xiàn)在差不多月了,按照工作的說(shuō)法,就是差不多過(guò)了三個(gè)月的試用期,準(zhǔn)備轉(zhuǎn)正了一般來(lái)說(shuō),差不多到了轉(zhuǎn)正的時(shí)候,會(huì)進(jìn)行總結(jié)或者分享會(huì)議那么今天我就把看過(guò)的一些學(xué)習(xí)資源主要是博客,博文推薦分享給大家。 1.前言 6月份開(kāi)始出沒(méi)社區(qū),現(xiàn)在差不多9月了,按照工作的說(shuō)法,就是差不多過(guò)了三個(gè)月的試用期,準(zhǔn)備轉(zhuǎn)正了!一般來(lái)說(shuō),差不多到了轉(zhuǎn)正的時(shí)候,會(huì)進(jìn)行總結(jié)或者分享會(huì)議!那么今天我就...
摘要:特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 本以為自己收藏的站點(diǎn)多,可以很快搞定,沒(méi)想到一入?yún)R總深似海。還有很多不足&遺漏的地方,歡迎補(bǔ)充。有錯(cuò)誤的地方,還請(qǐng)斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應(yīng)和斧正,會(huì)及時(shí)更新,平時(shí)業(yè)務(wù)工作時(shí)也會(huì)不定期更...
閱讀 2190·2021-10-08 10:05
閱讀 2042·2021-09-22 15:31
閱讀 3222·2021-09-22 15:13
閱讀 3753·2021-09-09 09:34
閱讀 2382·2021-09-03 10:46
閱讀 3303·2019-08-30 15:56
閱讀 1838·2019-08-30 15:53
閱讀 2498·2019-08-30 15:44