NodeJS與Django協(xié)同應(yīng)用開(kāi)發(fā)(0) —— node.js 基礎(chǔ)知識(shí)


系列目錄


不管怎樣嗦锐,當(dāng)你想要分享一個(gè)東西的時(shí)候你就逃不開(kāi)要解釋它是什么北滥,它是做什么用的。所以作為基礎(chǔ)知識(shí)儲(chǔ)備,這里就介紹一下node.js以及其最重要的模塊之一Socket.io髓废。

node.js

對(duì)于node.js最多的介紹就是:它是基于異步事件驅(qū)動(dòng)的高性能非阻塞IO框架捐康。

所謂非阻塞IO模型(non-blocking I/O model)白群,講到這個(gè)恐怕得從最初的服務(wù)器網(wǎng)絡(luò)模型說(shuō)起屈芜。
最初的服務(wù)器都是單進(jìn)程的阻塞IO,所有的請(qǐng)求都在同一個(gè)進(jìn)程里連續(xù)處理喻粹,如果當(dāng)前請(qǐng)求耗費(fèi)了較長(zhǎng)的CPU時(shí)間蟆融,那么其他后續(xù)所有請(qǐng)求都要等待這個(gè)請(qǐng)求處理結(jié)束后才能處理,而在處理期間這個(gè)進(jìn)程也會(huì)被掛起守呜。所謂是一卡全都卡型酥。
在這之后發(fā)展出的是多進(jìn)程多線(xiàn)程的網(wǎng)絡(luò)模型。首先是簡(jiǎn)單的多進(jìn)程模型:對(duì)于每一個(gè)連接都分配一個(gè)進(jìn)程查乒。這種做法簡(jiǎn)單粗暴得解決了一個(gè)請(qǐng)求阻塞導(dǎo)致全部請(qǐng)求都阻塞的問(wèn)題冕末,在請(qǐng)求量稍高但是不那么高的場(chǎng)景下完全足夠了。但是當(dāng)請(qǐng)求量一旦多起來(lái)侣颂,就又暴露出2個(gè)缺點(diǎn):

  1. 一個(gè)進(jìn)程所需的系統(tǒng)資源是不容忽視的,但是相比處理單個(gè)請(qǐng)求來(lái)說(shuō)又顯得殺雞用牛刀枪孩,高并發(fā)情況下系統(tǒng)資源極易耗盡憔晒。
  2. 同時(shí)能夠處理的進(jìn)程數(shù)取決于CPU核數(shù),進(jìn)程越多就意味著更頻繁的進(jìn)程調(diào)度蔑舞,也就意味著更多的時(shí)間被花在了切換進(jìn)程上拒担,導(dǎo)致整個(gè)系統(tǒng)的性能下降。
    于是又加入了多線(xiàn)程模型攻询,讓一個(gè)進(jìn)程可以處理多個(gè)請(qǐng)求从撼,以求降低系統(tǒng)資源的消耗。雖然多線(xiàn)程對(duì)于上述2個(gè)問(wèn)題都能有所改善钧栖,但是治標(biāo)不治本低零。創(chuàng)建線(xiàn)程開(kāi)銷(xiāo)小于創(chuàng)建進(jìn)程,切換線(xiàn)程開(kāi)銷(xiāo)也小于切換進(jìn)程(原因在于切換進(jìn)程涉及到換頁(yè)拯杠,涉及到代碼段換入換出掏婶,線(xiàn)程不涉及代碼段,只涉及數(shù)據(jù)段潭陪,也就是寄存器狀態(tài)和棧狀態(tài))雄妥,不過(guò)這只是把壓力閾值提高了一些而已最蕾,依然有一部分系統(tǒng)資源、CPU時(shí)間浪費(fèi)在了非處請(qǐng)請(qǐng)求上老厌。

到這里為止所說(shuō)的都還是阻塞IO模型瘟则,也就是一個(gè)處理請(qǐng)求的單元從收到請(qǐng)求,處理請(qǐng)求枝秤,到返回結(jié)果之間都是線(xiàn)性的醋拧,任何一步因?yàn)槿魏卧蜃枞硕紩?huì)導(dǎo)致這個(gè)處理單元的阻塞,并被掛起宿百。假如我們?cè)谝粋€(gè)請(qǐng)求的處理過(guò)程中需要查詢(xún)數(shù)據(jù)庫(kù)趁仙,或是依賴(lài)外部服務(wù),而這些操作又有很大的延遲垦页,那么在這段時(shí)間內(nèi)處理單元就會(huì)被掛起雀费,但由于這個(gè)請(qǐng)求沒(méi)有處理完,資源就不能拿出來(lái)處理其他的請(qǐng)求痊焊。所以哪怕服務(wù)負(fù)載特別高盏袄,資源的利用率也不高。所以就催生出了非阻塞IO模型薄啥。
在非阻塞IO模型里辕羽,最重要的一點(diǎn)就是任何操作都不會(huì)將當(dāng)前處理單元掛起,從而能夠允許其執(zhí)行之后的請(qǐng)求垄惧。這么做的好處在于更大化得利用了CPU時(shí)間刁愿,讓CPU時(shí)刻都在處理需要處理的事務(wù)。所以在這種模型下到逊,多進(jìn)程多線(xiàn)程就顯得沒(méi)那么必要铣口,只要能夠完全利用CPU的核數(shù),單線(xiàn)程也完全足夠觉壶,且性能還要優(yōu)于之前的模型脑题。這也是為什么現(xiàn)在的負(fù)載均衡器都建議按照CPU核數(shù)來(lái)部署應(yīng)用。

舉個(gè)例子铜靶,假設(shè)我們只有一個(gè)進(jìn)程(單線(xiàn)程)叔遂,此時(shí)來(lái)了3個(gè)請(qǐng)求,第一個(gè)請(qǐng)求需要查詢(xún)數(shù)據(jù)庫(kù)争剿,耗時(shí)500ms已艰,第二個(gè)請(qǐng)求需要調(diào)用外部服務(wù),耗時(shí)2000ms蚕苇,第三個(gè)請(qǐng)求查詢(xún)系統(tǒng)時(shí)間旗芬,耗時(shí)5ms。
在普通的阻塞IO模型里捆蜀,第一個(gè)請(qǐng)求來(lái)了之后先花500ms處理完疮丛,再花2000ms處理第二個(gè)請(qǐng)求幔嫂,再花5ms處理第三個(gè)請(qǐng)求。也就是說(shuō)第一個(gè)用戶(hù)500ms后得到了結(jié)果誊薄,第二個(gè)用戶(hù)卻用了2500ms得到結(jié)果履恩,第三個(gè)用戶(hù)僅僅只要查一下時(shí)間卻用了2505ms才得到結(jié)果。
而在非阻塞IO模型里呢蔫,同樣第一個(gè)請(qǐng)求過(guò)來(lái)后切心,查詢(xún)工作交給數(shù)據(jù)庫(kù),緊接著就開(kāi)始處理第二個(gè)請(qǐng)求片吊。同樣任務(wù)交給外部服務(wù)后绽昏,就開(kāi)始處理第三個(gè)請(qǐng)求。第三個(gè)請(qǐng)求很快就得到了結(jié)果俏脊,并返回給了用戶(hù)全谤,此時(shí)才經(jīng)過(guò)了5ms。在500ms的時(shí)間點(diǎn)爷贫,數(shù)據(jù)庫(kù)查詢(xún)工作結(jié)束认然,并返回給了第一個(gè)用戶(hù),在2000ms的時(shí)間點(diǎn)漫萄,外部服務(wù)返回了結(jié)果卷员,于是就返回給了第二個(gè)用戶(hù)。

下面這個(gè)表格就很清楚的展示了兩種模型的差異腾务。

發(fā)起請(qǐng)求到獲得結(jié)果時(shí)間表 阻塞IO模型 非阻塞IO模型
用戶(hù)1 500ms 500ms
用戶(hù)2 2500ms 2000ms
用戶(hù)3 2505ms 5ms

可以看出毕骡,非阻塞IO模型在請(qǐng)求量很多的時(shí)候,對(duì)于每一個(gè)用戶(hù)而言都有很好的體驗(yàn)岩瘦。

這一系列的演化挺峡,舉個(gè)例子,就好比有一個(gè)水庫(kù)需要排水担钮,最初你只有一個(gè)水管(單進(jìn)程)排水,突然有些水草把管子堵住了(當(dāng)前請(qǐng)求阻塞)尤仍,那在你把水草清理掉之前水都流不出來(lái)(所有請(qǐng)求阻塞)箫津。后來(lái)你決定再多買(mǎi)一些水管(多進(jìn)程),但是受財(cái)力限制你只能買(mǎi)100根(系統(tǒng)資源耗盡)宰啦。不過(guò)水草堵了之后依然需要人力來(lái)清理苏遥,但是依然財(cái)力所限你只能請(qǐng)4個(gè)工人(CPU核數(shù)),而工人大部分時(shí)間又花在了在水管間走來(lái)走去赡模,而不是實(shí)際清理水草上(進(jìn)程切換)田炭。這時(shí)候有個(gè)公司過(guò)來(lái)找你說(shuō)他們有種技術(shù)可以把25根管子包進(jìn)一個(gè)大管子里,看上去你只用了4個(gè)水管排水(多線(xiàn)程)漓柑,而且還比原來(lái)便宜(減少系統(tǒng)資源開(kāi)銷(xiāo))教硫。但是水管依然會(huì)堵叨吮,工人依然要找究竟哪個(gè)小管子堵了(線(xiàn)程依然需要切換)。再后來(lái)又有個(gè)公司過(guò)來(lái)找你說(shuō)有一套新型管子瞬矩,能夠在水草堵住的時(shí)候自動(dòng)切換到備用水管茶鉴,并自動(dòng)開(kāi)始清理水草,永遠(yuǎn)能夠讓水順利流出(非阻塞模型)景用,價(jià)值是原來(lái)的一個(gè)工人和25根水管的總和涵叮。于是你非常開(kāi)心的辭退了所有工人,賣(mài)了原先的所有水管伞插,買(mǎi)了4套新型管子(最大化利用CPU核數(shù))割粮。此后就再也不用擔(dān)心水排不出了。

這就是非阻塞IO模型媚污,而node.js的設(shè)計(jì)初衷就是搭建靈活的網(wǎng)絡(luò)應(yīng)用舀瓢,于是在此之上選用了JavaScript這一靈活的語(yǔ)言和異步事件驅(qū)動(dòng)設(shè)計(jì)。

所謂事件驅(qū)動(dòng)(event-driven)杠步,通俗來(lái)講就是發(fā)生了什么事氢伟,我們才做相應(yīng)的處理。這里的事件可以是一個(gè)用戶(hù)操作幽歼,可以是一次內(nèi)容變化朵锣,也可以是一次網(wǎng)絡(luò)請(qǐng)求,甚至可以是一次系統(tǒng)異常甸私。凡是我們關(guān)心的诚些,都可以成為事件,然后我們?cè)僮鱿鄳?yīng)的處理皇型。

而異步(asynchronous communication)的意思就是說(shuō)诬烹,當(dāng)一個(gè)調(diào)用到來(lái)時(shí),并不等到有結(jié)果了再返回弃鸦,而是直接返回绞吁,有結(jié)果了再通知調(diào)用方。
同步與異步唬格、阻塞與非阻塞家破,看上去非常相似但本質(zhì)是不同的。同步異步關(guān)心的是消息通信機(jī)制购岗,阻塞非阻塞關(guān)心的是等待調(diào)用結(jié)果時(shí)的狀態(tài)汰聋。

以下內(nèi)容引用自知乎用戶(hù) 盧毅 在問(wèn)題怎樣理解阻塞非阻塞與同步異步的區(qū)別?中的回答:

[同步異步]
舉個(gè)通俗的例子:
你打電話(huà)問(wèn)書(shū)店老板有沒(méi)有《分布式系統(tǒng)》這本書(shū)喊积,如果是同步通信機(jī)制烹困,書(shū)店老板會(huì)說(shuō),你稍等乾吻,”我查一下"髓梅,然后開(kāi)始查啊查拟蜻,等查好了(可能是5秒,也可能是一天)告訴你結(jié)果(返回結(jié)果)女淑。
而異步通信機(jī)制瞭郑,書(shū)店老板直接告訴你我查一下啊,查好了打電話(huà)給你鸭你,然后直接掛電話(huà)了(不返回結(jié)果)屈张。然后查好了,他會(huì)主動(dòng)打電話(huà)給你袱巨。在這里老板通過(guò)“回電”這種方式來(lái)回調(diào)阁谆。

[阻塞非阻塞]
還是上面的例子,
你打電話(huà)問(wèn)書(shū)店老板有沒(méi)有《分布式系統(tǒng)》這本書(shū)愉老,你如果是阻塞式調(diào)用场绿,你會(huì)一直把自己“掛起”,直到得到這本書(shū)有沒(méi)有的結(jié)果嫉入,如果是非阻塞式調(diào)用焰盗,你不管老板有沒(méi)有告訴你,你自己先一邊去玩了咒林, 當(dāng)然你也要偶爾過(guò)幾分鐘check一下老板有沒(méi)有返回結(jié)果熬拒。
在這里阻塞與非阻塞與是否同步異步無(wú)關(guān)。跟老板通過(guò)什么方式回答你結(jié)果無(wú)關(guān)垫竞。

而node.js在運(yùn)行時(shí)是采用單線(xiàn)程架構(gòu)的澎粟,又綜合了異步與非阻塞的優(yōu)點(diǎn),這就是為什么它還能保持高性能的原因欢瞪。至于為什么node.js選用了JavaScript和異步事件驅(qū)動(dòng)活烙,那就不是這里論述的話(huà)題了,只能說(shuō)它就是這么選了遣鼓,它樂(lè)意啸盏。

題外話(huà):
node.js選擇了JavaScript,所以就選擇了Google V8引擎骑祟,而原本V8是為了瀏覽器所設(shè)計(jì)的高性能js解釋器回懦,因此并不具備多線(xiàn)程能力,所以node.js也只能是單線(xiàn)程架構(gòu)曾我。但我認(rèn)為如果技術(shù)上能夠讓node.js支持多線(xiàn)程,性能并不會(huì)高于單線(xiàn)程健民。引入多線(xiàn)程就勢(shì)必引入鎖抒巢,在某些情況下加鎖的開(kāi)銷(xiāo)是不能忽略的,所以不見(jiàn)得多線(xiàn)程就是好秉犹。不過(guò)單線(xiàn)程的node.js并不能100%發(fā)揮出多核CPU的能力蛉谜,所以通過(guò)child_process.fork()稚晚,也就是現(xiàn)在的cluster模塊,允許node在多進(jìn)程下編程型诚。這樣更加能夠利用硬件資源來(lái)支撐高并發(fā)高訪問(wèn)量客燕。

Socket.io

相比node.js, socket.io就簡(jiǎn)單得多了狰贯。這是一個(gè)用來(lái)構(gòu)建實(shí)時(shí)web應(yīng)用的JavaScript庫(kù)也搓,對(duì)于瀏覽器的客戶(hù)端和后臺(tái)服務(wù)器端有兩套接口相似的庫(kù),與node.js相同涵紊,它也是事件驅(qū)動(dòng)的傍妒。
多數(shù)情況下socket.io是基于websocket協(xié)議的,但是對(duì)于不支持的瀏覽器它也能夠自動(dòng)回退到flash或是長(zhǎng)輪詢(xún)摸柄。
socket.io的好處就在于自動(dòng)選擇合適的協(xié)議颤练,簡(jiǎn)單易上手的api∏海可以說(shuō)node.js的熱度有相當(dāng)一部分是由socket.io撐起來(lái)的嗦玖。
對(duì)于socket.io也沒(méi)有那么多可以介紹的,各種特性實(shí)例代碼一看便知跃脊,所以這篇文章就先寫(xiě)到這吧宇挫,后文會(huì)搭建出一套node.js+socket.io+Django+redis的原型,更詳細(xì)的內(nèi)容可以移步那里匾乓。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捞稿,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拼缝,更是在濱河造成了極大的恐慌娱局,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咧七,死亡現(xiàn)場(chǎng)離奇詭異衰齐,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)继阻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)耻涛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人瘟檩,你說(shuō)我怎么就攤上這事抹缕。” “怎么了墨辛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵卓研,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)奏赘,這世上最難降的妖魔是什么寥闪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮磨淌,結(jié)果婚禮上疲憋,老公的妹妹穿的比我還像新娘。我一直安慰自己梁只,他們只是感情好缚柳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著敛纲,像睡著了一般喂击。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淤翔,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天翰绊,我揣著相機(jī)與錄音,去河邊找鬼旁壮。 笑死监嗜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抡谐。 我是一名探鬼主播裁奇,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼麦撵!你這毒婦竟也來(lái)了刽肠?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤免胃,失蹤者是張志新(化名)和其女友劉穎音五,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體羔沙,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡躺涝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扼雏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坚嗜。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖诗充,靈堂內(nèi)的尸體忽然破棺而出苍蔬,到底是詐尸還是另有隱情,我是刑警寧澤蝴蜓,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布碟绑,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蜈敢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一汽抚、第九天 我趴在偏房一處隱蔽的房頂上張望抓狭。 院中可真熱鬧,春花似錦造烁、人聲如沸否过。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)苗桂。三九已至,卻和暖如春告组,著一層夾襖步出監(jiān)牢的瞬間煤伟,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工木缝, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留便锨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓我碟,卻偏偏與公主長(zhǎng)得像放案,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矫俺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容