王金龍,宋 斌,丁 銳
(1.南京理工大學(xué),江蘇 南京 210094;2.中國鐵通集團(tuán)有限公司 泰州分公司,江蘇 泰州 225300)
Node.js:一種新的Web應(yīng)用構(gòu)建技術(shù)
王金龍1,宋 斌1,丁 銳2
(1.南京理工大學(xué),江蘇 南京 210094;2.中國鐵通集團(tuán)有限公司 泰州分公司,江蘇 泰州 225300)
現(xiàn)如今,有很多種Web應(yīng)用程序開發(fā)語言。在Web應(yīng)用程序開發(fā)過程中,大部分語言都要解決多線程問題。而且這些Web應(yīng)用程序都要部署在第三方Web服務(wù)器上,如:Apache,Tomcat,Nginx等。近期一種基于I/O事件驅(qū)動模型服務(wù)器端的JavaScript運(yùn)行環(huán)境——Node.js得到了廣泛的關(guān)注和應(yīng)用。通過對同步阻塞語言PHP和異步非阻塞的Node.js構(gòu)建的Web應(yīng)用程序做一些性能上的比較,發(fā)現(xiàn)在高并發(fā)請求的情況下,Node.js構(gòu)建的服務(wù)器比PHP構(gòu)建的應(yīng)用程序的響應(yīng)時間短、吞吐率高。最終得出結(jié)論Node.js在構(gòu)建快速、可擴(kuò)展的Web應(yīng)用程序方面的優(yōu)勢大于PHP。
Web服務(wù)器;異步非阻塞;事件驅(qū)動模型;Node.js
早期,PHP這門服務(wù)器端腳本語言一直受到Web應(yīng)用程序的開發(fā)者們青睞,然而JavaScript一直被人們認(rèn)為是前端的腳本開發(fā)語言,隨著Node.js的出現(xiàn),JavaScript得到了大家更多的關(guān)注。Node.js是建立在Chrome的JavaScript運(yùn)行時之上的平臺,它用于構(gòu)建快速、可擴(kuò)展的網(wǎng)絡(luò)應(yīng)用程序。Node.js使用一種事件驅(qū)動、非阻塞的I/O模型,這也使得跨分布式設(shè)備的數(shù)據(jù)密集型實時應(yīng)用更加輕量、高效和完美[1]。
目前,國內(nèi)外很多大公司都在將他們的部分產(chǎn)品的技術(shù)棧向Node.js轉(zhuǎn)變。國外的有,知名團(tuán)購網(wǎng)站Grou?pon將其站點從Ruby on Rails全面遷移到了Node.js.Groupon團(tuán)隊的開發(fā)人員表示,Rails非常適合小型團(tuán)隊的快速開發(fā),可以讓網(wǎng)站快速啟動并運(yùn)行起來,這對于初期功能不斷變化的Groupon來說,是個不錯的選擇。但是,隨著Groupon的發(fā)展和新產(chǎn)品的不斷推出,這個代碼庫越來越大,有太多的開發(fā)者在同一個代碼庫工作,他們很難在本地運(yùn)行并測試產(chǎn)品。因此,Groupon團(tuán)隊評估了不同的軟件棧,想尋找一個能夠解決這些問題的方案,有效處理大量傳入的HTTP請求、使并行API請求服務(wù)于每一個HTTP請求、將結(jié)果渲染為HTML5,并可以有效實現(xiàn)監(jiān)控、部署和支持。該團(tuán)隊使用不同的技術(shù)棧開發(fā)了原型,并做了測試,最終發(fā)現(xiàn)Node.js是個非常適合的解決方案。遷移之后,Groupon成為全球最大的Node.js部署產(chǎn)品之一,也為之帶來下列好處:頁面加載比之前快了50%;與之前相比,處理相同的流量所使用的硬件資源更少;團(tuán)隊可以獨立地更改、部署各自負(fù)責(zé)的模塊;網(wǎng)站功能和設(shè)計實現(xiàn)可以快速迭代。鑒于性能和可擴(kuò)展性方面的原因,Linked In將其移動設(shè)施的后臺Ruby on Rails替換成Node.js。
國內(nèi)的Node.js應(yīng)用主要有,淘寶的數(shù)據(jù)平臺、網(wǎng)易開源的pomelo實時框架和有道詞典等。MyFox是淘寶一個針對海量統(tǒng)計數(shù)據(jù)設(shè)計的高性能分布式MySQL集群中間層,負(fù)責(zé)從其中提取數(shù)據(jù)、計算并輸出統(tǒng)計結(jié)果。起初MyFox使用PHP編寫,但是遇到了很多問題。如PHP是單線程的,MySQL又需要阻塞查詢,因此很難并發(fā)請求數(shù)據(jù),最終項目組決定使用Node.js實現(xiàn)MyFox。pomelo是基于Node.js的高性能、分布式游戲服務(wù)器框架。它包括基礎(chǔ)的開發(fā)框架和相關(guān)的擴(kuò)展組件。網(wǎng)易選擇Node.js的原因是,Node.js天生就是做多進(jìn)程開發(fā)的,多個節(jié)點互相通訊交織在一起組成了分布式系統(tǒng);單線程的應(yīng)用模型處理游戲邏輯是最簡單,最不容易出錯的,而且不可能出現(xiàn)死鎖、鎖競爭的情況;游戲是非常I/O密集型的應(yīng)用,而Node.js生來就是為I/O而生的。
Node.js是Web服務(wù)器技術(shù)的新寵兒。與此同時,PHP這個傳統(tǒng)的Web應(yīng)用程序使用的語言,自誕生以來,褒貶不一。大家可能會說對語言的評論是沒有意義的,但是有些評論的確是得到權(quán)衡的。與PHP相比,你不必使用一個獨立的HTTP服務(wù)器,把Node.js應(yīng)用部署在Nginx下也是十分常見的,但不是必須的。因此,一個典型的Web應(yīng)用程序的核心就是一個Web服務(wù)器的實現(xiàn)。比較Node.js和PHP。其實,真正比較的是Node.js和PHP+Apache2(或者其他的HTTP服務(wù)器)。所以為了論證Node.js構(gòu)建的Web應(yīng)用程序在高并發(fā)請求下的性能優(yōu)勢,本文的比較實驗用的是Apache2和mod_php,因為它們目前是最流行的配置。
為了使比較更加的有理可據(jù),實驗用PHP5和Node.js創(chuàng)建了一個簡單的Web應(yīng)用程序。為了對兩種架構(gòu)的I/O性能做比較,該應(yīng)用程序從測試數(shù)據(jù)庫的用戶表中讀出前50行數(shù)據(jù),并且以JSON字符串的形式輸出到頁面。并通過開源的服務(wù)器性能測試工具Siege對兩者分別進(jìn)行50,100,150,200,250和300個并發(fā)情況下的壓力測試。保持應(yīng)用程序簡單的好處一是不必過問兩種語言的實現(xiàn)細(xì)節(jié),更重要的是,并非測試代碼的能力,真正測試的是兩種結(jié)構(gòu)的差別。實驗服務(wù)器和實驗環(huán)境配置如下:
硬件環(huán)境:Intel Core i5?3337U CPU@1.80 GHz,4 GB RAM。
軟件環(huán)境:Ubuntu 12.10 x64,Apache 2.2.22,PHP 5.4.6,Node.js 0.10.28,MySQL 5.5.37、服務(wù)器性能測試工具Siege。
從上面的代碼可以看出,Node.js是通過回調(diào)函數(shù)(即函數(shù)作為參數(shù))實現(xiàn)異步操作,而PHP是完全的同步編程風(fēng)格。而且,兩段代碼都能實現(xiàn)上述的功能。雖然PHP腳本明顯比Node.js短,但是,PHP不必實現(xiàn)一個完整的HTTP服務(wù)器,而Node.js只需要一句代碼(即http.createServer)就可以創(chuàng)建一個HTTP服務(wù)器。
圖1顯示在不同并發(fā)數(shù)下,Node.js構(gòu)建的服務(wù)器每秒鐘處理的事務(wù)數(shù)明顯高于PHP應(yīng)用。圖2顯示Node.js構(gòu)建的服務(wù)器的吞吐率維持在0.7 MB/s上下波動,而部署在Apache2服務(wù)器上PHP應(yīng)用的吞吐率則維持在0.2 MB/s上下波動。
圖1 不同并發(fā)數(shù)下的服務(wù)器每秒處理的事務(wù)數(shù)
圖2 不同并發(fā)數(shù)下的服務(wù)器的吞吐率
1.2.1 多線程與單進(jìn)程
實際上,上面的實驗結(jié)果并不奇怪,只是表明了兩種解決方案之間的架構(gòu)差異。PHP本身不是多線程的,但是Apache2支持多線程,一個請求對應(yīng)一個Apache線程。每個請求都有一個獨立的PHP線程運(yùn)行,請求之間的PHP環(huán)境相互獨立,互不影響。此外,每次啟動一個線程,都會占用一定大小的內(nèi)存,CPU上下文環(huán)境的切換也會帶來一定的開銷。
然而,Node.js構(gòu)建的Web服務(wù)器是單進(jìn)程的,一個進(jìn)程中保持一個活躍的請求處理線程。所以內(nèi)部沒有不同請求實例與父進(jìn)程之間通信這種情況。相比PHP/Apache,Node.js的內(nèi)存使用更加高效,Apache的每個并發(fā)請求都會占用一定的內(nèi)存,但是,Node.js不同請求都是共享內(nèi)存的。
由于Apache服務(wù)器上每個請求都是相互獨立,而服務(wù)器的內(nèi)存又是有限的,所以其必須在并發(fā)請求數(shù)和內(nèi)存之間做一個權(quán)衡。然而,Node.js不同請求共享內(nèi)存的優(yōu)勢,因此,Node.js構(gòu)建的服務(wù)器每秒處理的請求數(shù)(即RPS)會高于Apache服務(wù)器,而RPS最終又會反應(yīng)到服務(wù)器的吞吐率,如圖2所示,Node.js構(gòu)建的服務(wù)器的吞吐率明顯高過PHP。
1.2.2 同步與異步
PHP語言是以同步阻塞的方式執(zhí)行的。它的優(yōu)點十分明顯,利于程序員順序編寫業(yè)務(wù)邏輯;它的缺點在小規(guī)模站點中基本不存在,但是在復(fù)雜的網(wǎng)絡(luò)應(yīng)用中,阻塞導(dǎo)致它無法更好的并發(fā)。
然而Node.js是異步I/O的,Web應(yīng)用已經(jīng)不再是單臺服務(wù)器就能勝任的時代了,在跨網(wǎng)絡(luò)的結(jié)構(gòu)下,并發(fā)已經(jīng)是現(xiàn)代編程中的標(biāo)準(zhǔn)配備了[2]。具體到實處,則可以從用戶體驗和資源分配這兩個方面說起。
在用戶體驗方面,Node.js的實質(zhì)是運(yùn)行在Chrome v8引擎上的JavaScript。在瀏覽器中JavaScript在單線程上執(zhí)行,而且還與UI渲染共用一個線程。這意味著Ja?vaScript在執(zhí)行的時候UI渲染和響應(yīng)是處于停滯狀態(tài)的。如果網(wǎng)頁獲取一個網(wǎng)絡(luò)資源,通過同步的方式獲取,那么JavaScript則需要等待資源完全從服務(wù)器端獲取后才能繼續(xù)執(zhí)行,這期間UI將停頓,不響應(yīng)用戶的交互行為。然而,如果采用異步請求,在下載資源期間,JavaScript和UI的執(zhí)行都不會處于等待狀態(tài)。但是,前端獲取資源的速度也取決于后端的響應(yīng)速度,所以Node.js中資源的I/O都是異步[3]。
從資源分配方面分析,在計算機(jī)資源中,通常I/O與CPU計算之間是可以并行進(jìn)行的。但是同步的編程模型導(dǎo)致的問題是,I/O的進(jìn)行會讓后續(xù)的任務(wù)等待,這造成資源不能被更好的利用。從實驗結(jié)果圖1可以看出,PHP的同步阻塞I/O問題導(dǎo)致其每秒處理的事務(wù)數(shù)明顯比異步非阻塞的Node.js低很多。而且,單線程同步編程模型會因阻塞I/O導(dǎo)致硬件資源得不到更優(yōu)的使用,多線程編程模型也因為編程中的死鎖、狀態(tài)同步等問題讓開發(fā)人員頭疼。Node.js在兩者之間給出了它的方案:利用單線程,遠(yuǎn)離多線程死鎖、狀態(tài)同步等問題;利用異步I/O,讓單線程遠(yuǎn)離阻塞,以更好的使用CPU。
1.2.3 測試結(jié)論
通過上述實驗,可以看出Node.js構(gòu)建的單進(jìn)程、異步非阻塞I/O的Web服務(wù)器在處理高并發(fā)請求上的優(yōu)勢。面對高并發(fā)的用戶請求,Node.js構(gòu)建的Web服務(wù)器能作出更快速的響應(yīng),而且能有效利用服務(wù)器的硬件資源。
以上分析了Node.js通過異步非阻塞I/O高效的處理并發(fā)請求的優(yōu)勢。但是Node.js如何在單線程的請求的局限下,處理并發(fā)請求。下面,本文將介紹Node.js處理并發(fā)請求機(jī)制及其適用的領(lǐng)域。
Node.js構(gòu)建的服務(wù)器是通過事件驅(qū)動模型來處理并發(fā)請求的。在Node.js中,所有的磁盤I/O都對應(yīng)一個事件,Node.js內(nèi)部有一個事件循環(huán)進(jìn)程,一直輪詢是否有事件發(fā)生。如果某個事件發(fā)生了,就會執(zhí)行相應(yīng)事件的事件處理函數(shù)(又稱回調(diào)函數(shù))。用流程圖表示,如圖3所示。
Node.js的I/O方法是嚴(yán)格的:異步的交互是它的規(guī)則。每個I/O操作都是通過高度嵌套的函數(shù)(即一個函數(shù)作為另一個函數(shù)的參數(shù))處理的。在極少數(shù)的情況下,Node.js開發(fā)人員才會用到同步執(zhí)行的函數(shù)。例如,為了刪除或者重命名文件,如果這個操作可能需要網(wǎng)絡(luò)或文件的I/O調(diào)用,控制邏輯會立即返回給調(diào)用者。但是,當(dāng)有一些情況發(fā)生時,例如,如果數(shù)據(jù)變?yōu)榭捎糜趶木W(wǎng)絡(luò)Socket讀取,輸出流準(zhǔn)備好寫操作或者有錯誤發(fā)生時,回調(diào)函數(shù)將被調(diào)用[4]。也正是由于Node.js異步回調(diào)的編程風(fēng)格,導(dǎo)致開發(fā)過程中到處都是callback,代碼不優(yōu)雅,但是因為Node.js社區(qū)的活躍,出現(xiàn)了許多第三方的模塊來解決“回調(diào)陷阱”[5]問題。相比于Node.js,PHP是同步阻塞的編程模型,代碼邏輯更容易理解。
圖3 事件驅(qū)動模型流程圖
Node.js本身就支持構(gòu)建HTTP服務(wù)器,而不需要借助第三方的Web服務(wù)器,所以用Node.js開發(fā)的Web應(yīng)用程序部署非常方便、高效。
正如本文上面提到的,Node.js非常適合以下情況:在響應(yīng)客戶端之前,預(yù)計可能有很高的流量,但所需的服務(wù)器端邏輯和處理不一定很多,Node.js發(fā)揮優(yōu)勢的典型示例如下:提供RESTful API的Web服務(wù)接收幾個參數(shù),解析它們,組合一個響應(yīng),并返回一個響應(yīng)給用戶。這是適合Node.js的理想情況,因為可以構(gòu)建它來處理數(shù)萬條連接,但是不需要處理大量邏輯,它本質(zhì)上只是從某個數(shù)據(jù)庫中查找一些值并將它們組成一個響應(yīng)。由于響應(yīng)是少量文本,請求也是少量的文本,因此流量不高,一臺機(jī)器甚至也可以處理最繁忙的公司的API需求[6]。在游戲數(shù)據(jù)統(tǒng)計方面,Node.js也發(fā)揮了很好的優(yōu)勢。當(dāng)生成很高級別的統(tǒng)計數(shù)據(jù)時,必須跟蹤海量信息,如果有數(shù)百萬玩家同時在線玩游戲,而且處于游戲中的不同位置,為了快速生成海量信息,Node.js是這種場景的一種很好的解決方案,因為它能采集游戲生成的數(shù)據(jù),對數(shù)據(jù)進(jìn)行最少的合并,然后對數(shù)據(jù)進(jìn)行排隊,以便將它們寫入數(shù)據(jù)庫。
但是,Node.js不適用在CPU密集型的應(yīng)用,例如CPU使用率高而I/O操作少的情況[7]。因為Node.js是單線程的,對于多核CPU的服務(wù)器,Node.js不能有效地利用所有的核心。
本文通過對Node.js構(gòu)建的Web服務(wù)器和PHP構(gòu)建的應(yīng)用程序做了性能上的比較,最終發(fā)現(xiàn),異步非阻塞的Node.js構(gòu)建的Web服務(wù)器在處理高并發(fā)請求方面的優(yōu)勢,但是它不適用于CPU密集型的應(yīng)用??偟膩碚f,Node.js完成了它提供快速可擴(kuò)展服務(wù)器目標(biāo)。Node.js使用了 Google的一個非??焖俚?JavaScript引擎,即v8引擎[8]。同時使用一個事件驅(qū)動設(shè)計來保持代碼最小且易于閱讀。所有這些因素促成了Node.js的理想目標(biāo),即編寫一個快速可擴(kuò)展的解決方案變得比較容易。與理解Node.js是什么同樣重要的是,理解它不是什么。Node.js并不只是Apache的一個替代品,它旨在使Web應(yīng)用程序更容易擴(kuò)展。事實遠(yuǎn)非如此,盡管 Node還處于初始階段,但它發(fā)展得非常迅速,社區(qū)參與度非常高,社區(qū)成員創(chuàng)建了大量優(yōu)秀模塊,一年之內(nèi),這個不斷發(fā)展的產(chǎn)品就有可能出現(xiàn)在您的企業(yè)中。
[1]MCLAUGHLIN Brett.What is node?[M].California:O'Reilly Media,2011.
[2]樸靈.深入淺出Node.js[M].北京:人民郵電出版社,2013.
[3]TILKOY Stefan,VINOSKI Steve.Node.js:using JavaScript to build high?performance network programs[J].IEEE Internet Computing,2010,14(6):80?83.
[4]趙昆.改變Web開發(fā)格局的新技術(shù)node.js[J].程序員,2011(7):124?125.
[5]CANTELON Mike,HOLOWAYCHUK T J.Node.js in action[M].America:Manning Publications,2013.
[6]RAUCH Guillermo.Smashing Node.js[M].America:Wiley,2012.
[7]LOUKIDESMike.New directions in web architecture[EB/OL].[2010?11?16].http://radar.oreilly.com/2010/11/new?directions?in?web?architec.htm l.
[8]VOID B Y.Node.js開發(fā)指南[M].北京:人民郵電出版社,2012.
Node.js:a new technology to build Web app lication
WANG Jin?long1,SONG Bin1,DING Rui2
(1.Nanjing University of Science&Technology,Nanjing 210094,China;2.China Tietong,Taizhou 225300,China)
Nowadays,there are many program languages to build Web application.During developing Web application,the most of languagesmust handlemultithreading problem.In addition,these Web application programsmust be deployed in a third?party Web server,such as Apache,Tomcat,Nginx and so on.Recently,Node.js,an event?driven server?side JavaScript envi?ronment based on I/O has been widely concerned and applied.In this paper,via comparing the performance of the Web applica?tion built by synchronous blocking PHP and asynchronous non?blocking Node.js,it is found that the response time of the Web server built by Node.js is shorter than PHP and the throughput of Node.js is higher than PHP in the case of high concurrent re?quests.A conclusion that Node.js is superior to PHP in building fast and scalableWeb application program is obtained eventually.
Web server;asynchronous non?blocking;event?driven model;Node.js
TN911?34
A
1004?373X(2015)06?0070?04
2014?09?24
王金龍(1989—),男,江蘇淮安人,碩士研究生。研究方向為計算機(jī)應(yīng)用技術(shù)。