淺析Node.js:一個“編碼就緒”服務(wù)器
Node是一個服務(wù)器端JavaScript解釋器,它將改變服務(wù)器應(yīng)該如何工作的概念。它的目標是幫助程序員構(gòu)建高度可伸縮的應(yīng)用程序,編寫能夠處理數(shù)萬條同時連接到一個(只有一個)物理機的連接代碼。本文探究了Node.js能解決哪些問題,它如何工作,如何運行一個簡單應(yīng)用程序,***,Node何時是以及何時不是一個好的解決方案。
Node旨在解決什么問題?
Node公開宣稱的目標是“旨在提供一種簡單的構(gòu)建可伸縮網(wǎng)絡(luò)程序的方法”。當(dāng)前的服務(wù)器程序有什么問題?我們來做個數(shù)學(xué)題。在Java和PHP這類語言中,每個連接都會生成一個新線程,每個新線程可能需要 2 MB 配套內(nèi)存。在一個擁有8GB RAM的系統(tǒng)上,理論上***的并發(fā)連接數(shù)量是4,000個用戶。隨著您的客戶端基礎(chǔ)的增長,您希望您的web應(yīng)用程序支持更多用戶,這樣,您必須添加更多服務(wù)器。當(dāng)然,這會增加業(yè)務(wù)成本,尤其是服務(wù)器成本、運輸成本和人工成本。除這些成本上升外,還有一個技術(shù)問題:用戶可能針對每個請求使用不同的服務(wù)器,因此,任何共享資源都必須在所有服務(wù)器之間共享。例如,在Java中,靜態(tài)變量和緩存需要在每個服務(wù)器上的JVMs之間共享。這就是整個web應(yīng)用程序架構(gòu)中的瓶頸:一個服務(wù)器能夠處理的并發(fā)連接的***數(shù)量。
Node解決這個問題的方法是:更改連接連接到服務(wù)器的方式。每個連接都創(chuàng)建一個進程,該進程不需要配套內(nèi)存塊,而不是為每個連接生成一個新的OS線程(并向其分配一些配套內(nèi)存)。Node聲稱它絕不會死鎖,因為它根本不允許使用鎖,它不會直接阻塞I/O調(diào)用。Node還宣稱,運行它的服務(wù)器能支持數(shù)萬個并發(fā)連接。事實上,Node通過將整個系統(tǒng)中的瓶頸從***連接數(shù)量更改到單個系統(tǒng)的流量來改變服務(wù)器面貌。
現(xiàn)在您有了一個能處理數(shù)萬條并發(fā)連接的程序,那么您能通過Node實際構(gòu)建什么呢?如果您有一個web應(yīng)用程序需要處理這么多連接,那將是一件很 “恐怖” 的事!那是一種“如果您有這個問題,那么它根本不是問題” 的問題。在回答上面的問題之前,我們先看看Node如何工作以及它被設(shè)計的如何運行。
Node肯定不是什么
沒錯,Node是一個服務(wù)器程序。但是,它肯定不像Apache或Tomcat。那些服務(wù)器是獨立服務(wù)器產(chǎn)品,可以立即安裝并部署應(yīng)用程序。通過這些產(chǎn)品,您可以在一分鐘內(nèi)啟動并運行一個服務(wù)器。Node肯定不是這種產(chǎn)品。Apache能添加一個PHP模塊來允許開發(fā)人員創(chuàng)建動態(tài)web頁,使用Tomcat的程序員能部署JSPs來創(chuàng)建動態(tài)web頁。Node肯定不是這種類型。
在Node的早期階段(當(dāng)前是version 0.4.6),它還不是一個“運行就緒”的服務(wù)器程序,您還不能安裝它,向其中放置文件,擁有一個功能齊全的web服務(wù)器。即使是要實現(xiàn)web服務(wù)器在安裝完成后啟動并運行這個基本功能,也還需要做大量工作。
Node如何工作
Node本身運行V8 JavaScript。等等,服務(wù)器上的JavaScript?沒錯,您沒有看錯。服務(wù)器端JavaScript 是一個相對較新的概念,這個概念是大約兩年前在developerWorks上討論Aptana Jaxer產(chǎn)品時提到的(參見參考資料)。盡管Jaxer一直沒有真正流行,但這個理念本身并不是遙不可及的 — 為何不能在服務(wù)器上使用客戶機上使用的編程語言?
什么使 V8?V8 JavaScript引擎是Google用于他們的Chrome瀏覽器的底層JavaScript引擎。很少有人考慮JavaScript在客戶機上實際做了些什么?實際上,JavaScript引擎負責(zé)解釋并執(zhí)行代碼。使用V8,Google創(chuàng)建了一個以C++編寫的超快解釋器,該解釋器擁有另一個獨特特征;您可以下載該引擎并將其嵌入任何 應(yīng)用程序。它不僅限于在一個瀏覽器中運行。因此,Node實際上使用Google編寫的V8 JavaScript引擎并將其重建為在服務(wù)器上使用。太***了!既然已經(jīng)有一個不錯的解決方案可用,為何還要創(chuàng)建一種新語言呢?
Node對什么有好處?
到此為止,應(yīng)該能夠回答“Node是什么” 這個問題了,但您可能還不清楚什么時候應(yīng)該使用它。這是一個需要提出的重要問題,因為Node對有一些東西有好處,但相反,對另一些東西而言,目前Node可能不是一個好的解決方案。您需要小心決定何時使用Node,因為在錯誤的情況下使用它可能會導(dǎo)致一個多余編碼的 LOT。
正如您此前所看到的,Node非常適合以下情況:您預(yù)計可能有很高的流量,而在響應(yīng)客戶端之前服務(wù)器端邏輯和處理所需不一定是巨大的。Node表現(xiàn)出眾的典型示例包括:
RESTful API
提供RESTful API的web服務(wù)接收幾個參數(shù),解析它們,組合一個響應(yīng),并返回一個響應(yīng)(通常是較少的文本)給用戶。這是適合Node的理想情況,因為您可以構(gòu)建它來處理數(shù)萬條連接。它還不需要大量邏輯;它只是從一個數(shù)據(jù)庫查找一些值并組合一個響應(yīng)。由于響應(yīng)是少量文本,入站請求時少量文本,因此流量不高,一臺機器甚至也可以處理最繁忙的公司的API需求。
Twitter隊列
想像一下像Twitter這樣的公司,它必須接收tweets并將其寫入一個數(shù)據(jù)庫。實際上,每秒幾乎有數(shù)千條 tweets 達到,數(shù)據(jù)庫不可能及時處理高峰時段需要的寫入數(shù)量。Node成為這個問題的解決方案的重要一環(huán)。如您所見,Node能處理數(shù)萬條入站tweets。它能迅速輕松地將它們寫入一個內(nèi)存排隊機制(例如 memcached),另一個單獨進程可以從那里將它們寫入數(shù)據(jù)庫。Node在這里的角色是迅速收集tweet并將這個信息傳遞給另一個負責(zé)寫入的進程。想象一下另一種設(shè)計 — 一個常規(guī) PHP 服務(wù)器自己試圖處理對數(shù)據(jù)庫的寫入 — 每個tweet將在寫入數(shù)據(jù)庫時導(dǎo)致一個短暫的延遲,這是因為數(shù)據(jù)庫調(diào)用正在阻塞通道。由于數(shù)據(jù)庫延遲,一臺這樣設(shè)計的機器每秒可能只能處理2000條入站tweets。每秒100萬條tweets需要500個服務(wù)器。相反,Node能處理每個連接而不會阻塞通道,從而能捕獲盡可能多的tweets。一個能處理50,000 條tweets的Node機器只需要20個服務(wù)器。
映像文件服務(wù)器
一個擁有大型分布式網(wǎng)站的公司(比如 Facebook 或 Flickr)可能會決定將所有機器只用于服務(wù)映像。Node將是這個問題的一個不錯的解決方案,因為該公司能使用它編寫一個簡單的文件檢索器,然后處理數(shù)萬條連接。Node將查找映像文件,返回文件或一個404錯誤,然后什么也不用做。這種設(shè)置將允許這類分布式網(wǎng)站減少它們服務(wù)映像、.js和 .css文件等靜態(tài)文件所需的服務(wù)器數(shù)量。
它對什么有壞處?
當(dāng)然,在某些情況下,Node并非理想選擇。下面是Node不擅長的領(lǐng)域:
動態(tài)創(chuàng)建的頁
目前,Node沒有提供一種默認方法來創(chuàng)建動態(tài)頁。例如,使用JavaServer Pages (JSP) 技術(shù)時,可以創(chuàng)建一個在 這樣的JSP代碼段中包含循環(huán)的index.jsp 頁。Node不支持這類動態(tài)的、HTML驅(qū)動的頁面。同樣,Node不太適合作為Apache和Tomcat這樣的網(wǎng)頁服務(wù)器。因此,如果您想在Node中提供這樣一個服務(wù)器端解決方案,必須自己編寫整個解決方案。PHP程序員不想在每次部署web應(yīng)用程序時都編寫一個針對Apache的PHP轉(zhuǎn)換器,當(dāng)目前為止,這正是Node要求您做的。
關(guān)系數(shù)據(jù)庫重型應(yīng)用程序
Node的目的是快速、異步和非阻塞。數(shù)據(jù)庫并不一定分享這些目標。它們是同步和阻塞的,因為讀寫時對數(shù)據(jù)庫的調(diào)用在結(jié)果生成之前將一直阻塞通道。因此,一個每個請求都需要大量數(shù)據(jù)庫調(diào)用、大量讀取、大量寫入的web應(yīng)用程序非常不適合Node,這是因為關(guān)系數(shù)據(jù)庫本身就能抵銷Node的眾多優(yōu)勢。(新的NoSQL數(shù)據(jù)庫更適合Node,不過那完全是另一個主題了。)
結(jié)語
問題是“什么是Node.js?” 應(yīng)該已經(jīng)得到解答。閱讀本文之后,您應(yīng)該能通過幾個清晰簡潔的句子回答這個問題。如果這樣,那么您已經(jīng)走到了許多編碼員和程序員的前面。我和許多人都談?wù)撨^Node,但它們對 Node究竟是什么一直很迷惑??梢岳斫?,他們具有的是Apache的思維方式 — 服務(wù)器是一個應(yīng)用程序,將HTML文件放入其中,一切就會正常運轉(zhuǎn)。而Node是目的驅(qū)動的。它是一個軟件程序,使用JavaScript來允許程序員輕松快速地創(chuàng)建快速、可伸縮的web服務(wù)器。Apache是運行就緒的,而ode是編碼就緒的。
Node完成了它提供高度可伸縮服務(wù)器的目標。它并不分配一個 “每個連接一個線程” 模型,而是使用一個 “每個連接一個流程” 模型,只創(chuàng)建每個連接需要的內(nèi)存。它使用Google的一個非??焖俚腏avaScript引擎:V8引擎。它使用一個事件驅(qū)動設(shè)計來保持代碼最小且易于閱讀。所有這些因素促成了Node的理想目標 — 編寫一個高度可伸縮的解決方案變得比較容易。
與理解Node是什么同樣重要的是,理解它不是什么。Node并不是Apache的一個替代品,后者旨在使PHP web應(yīng)用程序更容易伸縮。事實確實如此。在Node的這個初始階段,大量程序員使用它的可能性不大,但在它能發(fā)揮作用的場景中,它的表現(xiàn)非常好。
將來應(yīng)該期望從Node得到什么呢?這也許是本文引出的最重要的問題。既然您知道了它現(xiàn)在的作用,您應(yīng)該會想知道它下一步將做什么。在接下來的一年中,我期待著Node提供與現(xiàn)有的第三方支持庫更好地集成?,F(xiàn)在,許多第三方程序員已經(jīng)研發(fā)了用于Node的插件,包括添加文件服務(wù)器支持和MySQL支持。希望Node開始將它們集成到其核心功能中。***,我還希望 Node支持某種動態(tài)頁面模塊,這樣,您就可以在HTML文件中執(zhí)行在PHP和JSP(也許是一個NSP,一個Node服務(wù)器頁)中所做的操作。***,希望有一天會出現(xiàn)一個 “部署就緒” 的Node服務(wù)器,可以下載和安裝,只需將您的HTML文件放到其中,就像使用Apache或Tomcat那樣。Node現(xiàn)在還處于初始階段,但它發(fā)展得很快,可能不久就會出現(xiàn)在您的視野中。
注:本文內(nèi)容是根據(jù)developerWorks作者Mike Abernethy的文章整理而來的,在Michael Abernethy的13年技術(shù)生涯中,他與各種不同的技術(shù)和客戶打交道。他目前是一名自由程序員,擅長Java高可用性和jQuery。他現(xiàn)在專注于富Internet 應(yīng)用程序,試圖同時實現(xiàn)應(yīng)用程序的復(fù)雜性和簡單性。他空閑時常常去打高爾夫球,更確切地說,是在灌木叢中尋找他打飛的高爾夫球。
【編輯推薦】