Node.js,一個基於GoogleV8引擎的Javascript運行環境

一、NodeJS簡介

    思考

      首先我們來思考一個問題:我們都知道幾乎所有現代主流瀏覽器都全面支持了ECMAScript 5.1版標準,而JavaScript的標準是ECMAScript那麼我們就容易認爲JavaScript是一種瀏覽器端的解釋型編程腳本。那麼脫離了瀏覽器,JavaScript還能夠解釋運行嗎? 答案是肯定的,也就是說脫離了瀏覽器,在特定環境下JavaScript還是能運行的。JavaScript向來以Web網頁的腳本語言而著稱,但現在也可以用在許多非瀏覽器環境,例如node.js或者Apache CouchDB。本文就是基於NodeJS來進行探討。

    NodeJS是什麼?

      根據百度百科解釋,Node.js是一套用來編寫高性能網絡服務器的JavaScript工具包。Node.js是一個可以快速構建網絡服務及應用的平臺,該平臺的構建是基於Chrome's JavaScript runtime,也就是說,實際上它是對GoogleV8引擎(應用於Google Chrome瀏覽器)進行了封裝。V8引 擎執行Javascript的速度非常快,性能非常好。

      NodeJS並不是提供簡單的封裝,然後提供API調用,如果是這樣的話那麼它就不會有現在這麼火了。Node對一些特殊用例進行了優化,提供了替代的API,使得V8在非瀏覽器環境下運行得更好。例如,在服務器環境中,處理二進制數據通常是必不可少的,但Javascript對此支持不足,因此,V8.Node增加了Buffer類,方便並且高效地 處理二進制數據。因此,Node不僅僅簡單的使用了V8,還對其進行了優化,使其在各環境下更加給力。

    Node.js的優點

      1、基於V8虛擬機,可構建高性能服務器

       V8引擎本身使用了一些最新的編譯技術。這使得用Javascript這類腳本語言編寫出來的代碼與用C這類高級語言寫出來的代碼性能相差無幾,卻節省了開發成本。對性能的苛求是Node的一個關鍵因素。 Javascript是一個事件驅動語言,Node利用了這個優點,編寫出可擴展性高的服務器。Node採用了一個稱爲“事件循環(event loop)”的架構,使得編寫可擴展性高的服務器變得既容易又安全。提高服務器性能的技巧有多種多樣。Node選擇了一種既能提高性能,又能減低開發複雜度的架構。這是一個非常重要的特性。併發編程通常很複雜且佈滿地雷。Node繞過了這些,但仍提供很好的性能。

      2、單線程

      Node.js可以在不新增額外線程的情況下,依然可以對任務進行並行處理 —— Node.js是單線程的。它通過事件輪詢(event loop)來實現並行操作,對此,我們應該要充分利用這一點 —— 儘可能的避免阻塞操作,取而代之,多使用非阻塞操作。

      3、可利用Javascript進行後臺開發

      雖然讓Javascript運行於服務器端不是Node的獨特之處,但卻是其一強大功能。不得不承認,瀏覽器環境限制了我們選擇編程語言的自由。任何服務器與日益複雜的瀏覽器客戶端應用程序間共享代碼的願望只能通過Javascript來實現。雖然還存在其他一些支持Javascript在服務器端 運行的平臺,但因爲上述特性,Node發展迅猛,成爲事實上的平臺。

      4、非阻塞IO

      Node採用一系列“非阻塞”庫來支持事件循環的方式。本質上就是爲文件系統、數據庫之類的資源提供接口。向文件系統發送一個請求時,無需等待硬盤(尋址並檢索文件),硬盤準備好的時候非阻塞接口會通知Node。該模型以可擴展的方式簡化了對慢資源的訪問, 直觀,易懂。尤其是對於熟悉onmouseover、onclick等DOM事件的用戶,更有一種似曾相識的感覺。

      5、RESTFUL API

二、爲何接觸NodeJS,我們的問題以及解決方案

      本人現在在IBM公司實習,參與公司雲辦公系統的項目研發,本人所在項目組主要負責在線電子表格的開發工作。項目前端開發是基於DOJO框架,後臺主要基於JAVA。項目功能性開發已經基本完成,但是在實際測試階段發現在編輯超過一定閾值的大數據的情況下系統開銷比較大,運行效率無法滿足要求。

      在經過大量跟蹤測試及分析後,基於系統的整體架構以及解決該性能問題,我們有兩套解決方案:1、由於現在系統詞法解析採用的是開源語法分析器ANTLR,而ANTLR在效率上還略有不足,因此我們決定基於ANTLR來進行二次開發,尋求一些改進;2、建立前端服務器,和後臺服務器進行分離。前端與後臺共同維護一致的數據模型,前端服務器主要解決運算方面的請求並將計算結果及時反饋用戶,然後將改變發送到後臺服務器,由後臺服務器進行持久化存盤、消息分發等一些操作。

      由於前端是基於DOJO框架進行的開發,爲了最大限度的重用前階段實現的功能代碼來我們考慮基於NodeJS來搭建前端服務器,並充分利用NodeJS的一些特性來實現系統性能的提高。

三、爲何選擇NodeJS

      我想不僅僅是Node.js,當我們要引入任何一種新技術前都必須要搞清楚幾個問題:

    • 我們遇到了什麼問題?
    • 這項新技術解決什麼問題,是否契合我們遇到的問題?
    • 我們遇到問題的多種解決方案中,當前這項新技術的優勢體現在哪兒?
    • 使用新技術,帶來哪些新問題,嚴重麼,我們能否解決掉?

      Server端阻塞是當前系統遇到的最大問題。在整個數據查詢的過程中,當前程序進程往往只是在等待結果的返回,這就造成了進程的阻塞。對於高併發、計算任務較大以及I/O密集行的網絡應用中,一方面進程很長時間處於等待狀態,另一方面爲了應付新的請求不斷的增加新的進程。這樣的浪費會導致系統支持QPS遠遠小於後端數據服務能夠支撐的QPS,成爲了系統的瓶頸。Node一向是這樣來標榜自己的:“在node中除了代碼,所有一切都是並行執行的”。這句話的意思是說,Node.js可以在不新增額外線程的情況下,依然可以對任務進行並行處理 。Node.js是單線程的,它通過事件輪詢(event loop)來實現並行操作,對此,我們應該要充分利用這一點 ,儘可能的避免阻塞操作,取而代之,多使用非阻塞操作。我們搭建前端服務器主要用於處理前端大量的公司計算並將計算結果及時呈現給用戶,所以能夠避免很多I/O阻塞操作,這樣就能充分利用NodeJS的優點同時也能夠滿足我們的需求。另外,我們前端基於的DOJO框架是基於JS的,而NodeJS在處理JavaScript的優勢在前面已有介紹,這裏不再贅述。

    JS適合解決阻塞問題

      解決阻塞可以引入事件處理機制解決這個問題,在查詢請求發起之前註冊數據加載事件的響應函數,請求發出之後立即將進程交出,而當數據返回後再觸發這個事件並在預定好的事件響應函數中繼續處理數據。而JavaScript,相對於其他語言,至少有兩個關鍵特性決定它特別適合完成這個任務。

     (一) JavaScript是一種函數式編程語言,函數編程語言最重要的數學基礎是λ演算(lambda calculus) ,即函數對象可以作爲其他函數對象的輸入(參數)和輸出(返回值)。這個特性使得爲事件指定回調函數變得很容易。特別是JavaScript還支持匿名函數,通過匿名函數的輔助,我們很容易實現回調。(二)JavaScript的另外一個重要語言特性:閉包(Closures)。該特性可以使異步回調的運行上下文保持,即"狀態保持"。

四、使用NodeJS帶來的問題以及解決方案

       阻塞式編程浪費了大量進程資源只是在等待,導致大量內存和cpu的浪費。在這方面Node.js好很多,但也正是因爲一些閉包等JavaScript內建機制也會導致資源的浪費。看下面的代碼:

       Js代碼:

複製代碼
1 function main(){ 
2     var id = "1"; 
3     var str = "..."; //這裏局部變量str存儲一個2M的字符串 
4     db.query("selcect name from persons where id=" + id,function(name){ 
5         output("person id:" + id + ", name:" + name);//n秒後數據返回後執行回調 
6     }); 
7 } 
8 main();
複製代碼

至少整個數據查詢過程中,變量str所使用的2M內存並不會被釋放,而str保持下去可能並沒有意義。前面已經解釋過閉包的原理,閉包並沒有智能到只包起來今後可能被訪問到的對象。

五、後記

      本文主要參考http://www.kuqin.com/webpagedesign/20110812/105100.html的博文分享,結合公司具體項目遇到的問題進行分析,充分運用NodeJS的特性來嘗試解決問題。作者本人由於項目需要剛剛開始學習NodeJS相關知識,後續會在自己學習的同時繼續總結一些經驗成果進行分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章