我為什么反對用Node
隨著無線端的快速普及,前后端分離技術走上前臺,而Node由于它的一些特性被工程師快速接受尤其是前端工程師,所以產生了很多Node是否會引 起新的技術變革的討論。我本人是淘系的一個Web開發人員,基本上經歷了淘系關于Node和Java技術選型討論的過程,所以今天我給大家推演一下在像淘 系這個環境下Node能否會成為主流的Web開發技術,當然后面也給出了我認為比較適合的場景。
Node火了
在百度中搜索Node可以得到105w個結果,圖書出版方面13年3月到15年6月2年時間有近20種相關的Node書出版,實踐方面國外公司 PayPal、LinkedIn、groupon也都在使用,國內大公司阿里、騰訊、百度也都有實踐項目在嘗試。這讓我想起了當初Nosql新出來是一樣 的場景,大家都一窩蜂的涌上去擁抱新技術,獲取新技術帶來的紅利。
Node很火的另一個推手是當前的無線技術流行,很多應用從傳統的PC開發要轉到無線等多端,這種情況下渲染層和邏輯層的分離變得重要起來,而Node剛好可以很好的渲染前端頁面,所以我們的開發同學不遺余力的在推廣Node技術。
Node能夠火起來最重要的原因還是它的確給我們的開發帶來了很多好處:
- 基于事件驅動
- 無阻塞I/O
Node還有其它一些優點如單線程、RESTful API等,總體來說Node是為輕量級的分布式的實時數據服務這類應用提供運行容器而設計的,這類應用很容易想到微博、非死book這類典型場景,需要非常實時化、個性化、高并發的數據服務。
為什么火了
今年由于無線終端的興起,后端要提供基于JSON API的數據接口非常普遍。目前來看公司還存在兩種形態:一個是無線作為新系統獨立存在于傳統PC系統;另外一種是將無線系統合并到老的PC系統,在一個 系統里同時支持多端服務。長期來看無線和PC系統的合并是必然,業務上以無線為主,PC僅僅作為一個終端而已,不可能存在無線和PC兩套業務邏輯。
那基于無線和PC業務合并,由一個系統提供多終端、多語言適配的角度來看,Node能否在其中扮演傳統服務端 MVC中的V角色?
要回答這個問題,我們再設想一下,在多端情形下,需要怎樣的交互:PC、手機端、Pad、TV、Car、Watch等其它移動終端。
是Native還是H5
當前移動端主要還是以Native實現為主,從用戶體驗角度來考慮Native的實現要比H5更流暢,同時Native還可以基于本地做很多在瀏覽器里不能做的優化,如大數據的存儲、可以定制的通信協議、更方便的保持長連接以及更容易實現的實時消息推送。
當然H5也有其無法比擬的優勢,客戶端更輕量級,服務端發布更迅速,不需要用戶升級版本等。長期來看移動端能否會向早期PC那樣也從富客戶端轉向瀏覽器呢?
我的判斷是未必,有幾個因素,首先Native實現性能優勢相比H5會好很多,當前移動端都在追求極致體驗的時代,無疑APP會比H5有很多的優 勢;其次,移動端屏幕較小,基于網頁的交互和APP相比還有很多限制。最重要的是不同的商家是主推帶有品牌標識的APP還是向統一的瀏覽器靠攏,從目前的 趨勢看,APP 會是手機端上爭奪的重點。所以推測直接基于手機端的瀏覽器的應用不會成為主流前端。
如何實現快速迭代
基于APP的Native如何解決客戶端更新和服務端的快速迭代,這個問題是當前正在著力解決的,目前為止有兩種思路:一種是客戶端用同一種技術 開發,然后通過工具編譯技術把它編譯成不同平臺上能夠執行的代碼,如當前的Reactor.js;另一種思路是將客戶端中經常需要更新的模塊做成動態推送 的,用模板+數據的方式,在不同的客戶端平臺上實現一個小的解析引擎來實現快速個性化的定制,目前手淘主要采用后面一種實現方式,當然前一種也正在嘗試。
那么再說回來,基于前面的這些推斷,多終端和服務端交互主要是數據+模板的方式為主,那么服務端提供格式化的數據將成為必然選項。所以涉及到的問 題就是服務端既要提供格式化的數據(Http JSON數據),又要支持傳統的PC的方式:基于JSON數據渲染出HTML頁面,所以很容易想到將渲染層獨立出來用Node完成。
真的靠譜嗎
既然Node可以帶來這么多好處,那么我們不妨就繼續向下推演,看是否真的很靠譜?下面看下Node在我們的實際的開發環境中如何使用,在引入Node之前我們有必要先介紹下當前Web服務端架構:
(點擊放大圖像)
圖1. 傳統的web架構
在當前這種架構下Node怎么融入進去呢?最保守的一種方案是將當前的Java Web中的VIEW層從MVC中獨立出來,交給Node來完成,Java Web只提供基于JSON數據接口給Node調用,架構圖變成了如下的形式:
(點擊放大圖像)
圖2. Node作為渲染層加入到傳統架構中
很明顯的差別是在我們當前的訪問路徑上多增加了一個Web代理層,而這一層和當前的Web服務器層怎么看都有點別扭,兩者同時存在始終覺得有一個 是多余的,那么Node能否替代掉Nginx成為Web代理服務器呢?理論上是完全沒問題的,就像我們用PHP來代替Java Web開發一樣,不過你放到具體的公司運維體系中,你會發現目前在Nginx上的防攻擊、限流、數據埋點、熱點cache等模塊都要在Node上重新開發 一遍,最重要的是用Node取代Nginx并不能帶來額外的好處,如果你說Node可以渲染頁面,那么Nginx的開發會和你討論Nginx lua模塊和Node哪個更合適,所以用Node取代Nginx作為代理服務器也不太現實。
那么Node能否取代前端臺的Web系統,成為主流的MVC框架呢?
未必
Node和Java Web一樣可以提供MVC管理功能,一個系統中同時存在兩套MVC框架顯然不合理,那么如果用Node 來替換Java Web的話,服務端的架構變成如下的:
(點擊放大圖像)
圖3. Node替代Java Web
從技術實現上這種架構沒什么大問題,就是用Node上的MVC框架如express來替代Java Web中Webx,也就是用JavaScript替換Java,以及整個運行容器和中間件都要替換,那么是否真的帶來那么大的好處呢?
我們從語言特性、開發效率和成本因素三個方面來看,Node作為后來者能否比我們現在的Java更優秀。
語言特性
JavaScript作為Node上運行的語言和Java相比,優缺點很明顯。JavaScript語法簡單,很容易編寫基于事件的驅動的實現。 但是JavaScript基于面向對象的描述能力偏弱,不像Java是真正的面向對象語言 ,同時JavaScript的對數據類型定義也比較單一,要么是數值類型要么是字符類型。很明顯Java更擅長構建復雜邏輯的大型應用程序,在這一點上 JavaScript明顯落于下風。
在語言運行效率上,JavaScript本來是解釋執行,而Java是編譯執行,但是由于Node做了優化,所以運行效率差別不大。
開發效率
開發效率可以從語言的復雜度、程序員培養、開發工具包的豐富性以及編碼效率幾個方面比較。
- 語言的復雜度。Java和JavaScript從開發角度都不需要關心內存的管理,都是基于虛擬機來管理內存,從并發角度來 看:JavaScript是基于事件觸發的,而Java是基于線程的,JavaScript更占優勢。另外JavaScript是無阻塞 I/O的,在I/O效率上JavaScript也更占優勢,雖然Java8也將更好的支持異步I/O。
- 程序員培養。目前Java語言仍然是僅次于c語言的第二大編程語言,而JavaScript排查第10位,Java程序員隊伍要比JavaScript大很多,很顯然Java程序員招聘要比JavaScript更容易一點。
- 開發工具包。一個語言的開發效率很多時候要這個語言的支持工具包和組件的豐富性,Java經過這么多年的發展,工具類庫已經非常豐富,幾乎你 想要的工具類庫都能在網上找到。JavaScript雖然也發展很長時間,但是基于JavaScript的工具類庫主要集中在前端,能夠直接用于Node 上的仍然很少,當然Node的社區非常活躍,可以預見Node的工具類庫增長也會非常迅速。但是短時間內要達到Java的規模尚需時日。
- 編碼效率。Java語言的運行基于JVM,但是Java的部署效率稍差,而JavaScript使測試更加簡單,容器重啟更快,但是debug機制仍然不完善,所以很難做debug測試。
成本因素
前面主要是從技術角度考慮,但是如果往Node遷移的話,成本也是一個考慮因素。
- 首先是學習成本。公司大部分是Java程序員要往Node遷移很明顯這個學習成本會非常巨大,即使這個遷移是逐漸的,長期來看仍然是要將一部 分Java程序員替換成JavaScript程序員,不管這個程序員是公司內培養的還是從外部招聘的,我們可以算一下帳,公司招聘一個程序員的成本有多 大:一個普通的工程師的年薪假定有10w以上,獵頭費一般是年薪的20%以上,也就是2w,再加上一個月的實習成本1w,加在一起約3w,對于一個有1w 以上開發的大公司成本可想而知,即使是招聘應屆生,由于應屆生的培養周期更長,所以學習成本會更高。
- 其次是環境成本。公司的基礎服務產品,如中間件都是基于Java開發的,如果要替換成JavaScript 必然要再開發一套,還有配套的運維工具等,這個成本也可想而知。
- 最后是維護成本。Java和JavaScript都是基于容器運行,JVM和v8引擎相比,程序員顯然對JVM更熟悉。另外從排查問題的難易程度來看針對JVM的工具顯然更完善。
從上面幾個方面來看,當前在阿里要讓JavaScript完全取代Java作為后端開發語言,基于Node用JavaScript 實現整個服務層邏輯顯然成本會比較高。
換個角度
我們再換一種角度推演一下,假如我們現在的Web系統都用Node實現,那必然有很多Java工程師會做Node的開發,因為我們現有的前端工程 師人數肯定是支撐不了現有的業務發展的。我們假定一部分Java工程師愿意學習JavaScript成為全棧工程師,但是是否同一個人愿意用兩種不同的語 言完成同一個任務呢,正常來說,如果我能用同一個方式完成全部工作,我為什么要把一個任務分成兩種不同的方式來完成,這顯然也不太合理。所以部分前端同學 通過要求后端同學也學習JavaScript,來達到讓后端同學來使用Node這顯然有點打錯算盤,不過后端同學學習JavaScript可以實現頁面的 JS交互邏輯倒是可以替代前端的工作。
怎么辦
基于前面的分析,Node不管是在現有基礎上單獨增加一層還是要整個替換Java Web層都不太合理,那是否意味著這種前后端分離的思路有沒有合理之處?有沒有更好的實現呢?
傳統的MVC Web軟件架構將渲染層獨立出來交由前端同學控制有其合理性,在當前的多終端開發模式下,將業務邏輯層和前端渲染層分離有利于提升后端的開發效率,后端只 需要關注后端的業務邏輯和數據的輸出,因為在Native開發下服務端只需要輸出JSON數據,客戶端的頁面渲染有客戶端同學完成。H5和PC需要的 HTML渲染統一交給前端同學完成有利于前端更好的開發模板,從以往的先畫好模板(HTML),給后端同學轉化成相應的模板(如Velocity或 JSP),然后再基于復雜的Java Web工程下調試頁面(前端要獨立的運行整個Java Web工程還是相當的困難)。而渲染層全部交給前端的話,前端同學和后端只需要約定好數據后,頁面完全由前端同學完成,減少了不少交流成本(不過從淘寶的 基于Node實踐來看,整個效率提升還不是那么明顯,大部分是把原本是后端的開發工作量轉嫁給前端了)。
還有一個重要的理由是前端有了渲染層的控制權,前端的開發體驗有了不小的提升,說白了就是前端從以往的配合角色轉變成一個Web渲染層的 Owner,更加有了主人翁角色,如果再維護Node的話,和以往的后端Java開發幾乎一樣了,而這種前端職責的提升恰恰是從后端削弱過來的,所以第一 個出來反對的肯定是后端同學,當前在阿里Node發展比較緩慢我想也有一點關系吧。
再說回來,我們一直討論的基于Node實現的前端分離方案,可以把他分解一下Node技術和前后端分離。很明顯前后端分離在當前多終端背景下有其合理性,但是是否一定要用Node來實現呢?答案是不一定。當前還有兩種方案:
將Node層代碼拋到Java體系上,如下圖:
(點擊放大圖像)
圖4. Node嵌入到Java中
當前的Java8(Nashorn)已經可以支持JavaScript的解析,而Avatar.JS可以將Node無縫遷移過來,但是經過測 試,Nashorn+Avatar.JS的執行效率太差,有4到10倍的性能下降,最好也有一半的下降,這樣很難達到工程級別的使用。
另外一種就是仍然在基于Java Web體系下,而是將渲染層獨立出來,渲染層和業務邏輯層仍然通過JSON(或者大對象)數據交互,使得渲染層既可以在Java上渲染也可以在Node上執行。如下圖所示:
(點擊放大圖像)
圖5. Java Web兼容Node的模板層
這種方式與前一種的區別是只做渲染引擎的適配,即模板在Node和Java上都可以解析,而不是把Node的整個MVC都搬過來,由于Node和 Java Web上都有控制邏輯(即MVC中的C),所以如果Node和Java中邏輯不一致會導致兩邊渲染出來的HTML不一致,所以需要把URL改造成滿足 RESTFULL的格式,盡量把C的邏輯簡單化。
上圖的架構正是目前我們在詳情系統上做的一個實踐,成功的關鍵是將XTPL的模板從Node上無縫遷移到Java上,另外就是保持頁面的路由盡量簡單,這樣前端在Node上開發的重點只是XTPL模板。這種解決方案達到幾個目的:
- 我們的后端系統完成的組件化改造,PC和無線邏輯統一起來了;
- 將渲染層獨立,渲染層后業務量邏輯層通過JSON數據對象交互;
- 前端開發同學完全掌握了XTPL+JS邏輯,有更多的掌控力;
- 前端開發頁面不需要依賴后端的Java系統,調試頁面可以在Node中完成;
- 系統的架構并沒有增加一層,運維上也沒有引入新的Node系統。
沒有無往不能的神器
前面介紹了在現有Java體系下,要將Node替換Java Web其實是比較困難的,所以沒有一個技術是無往不能的神器,但是是否意味著Node就沒有應用場景了呢?肯定不是,下面這些情況下Node很有用武之地。
創業公司很合適,尤其當創始人之一是熟悉前端的同學的話,用Node實現Web系統很合適,Node和PHP一樣具備快速發布的優勢,代碼 copy上去就生效,甚至不需要重啟服務器,這一點相比Java有很大的優勢。當業務邏輯還沒有非常復雜時,JavaScript語言的弱點也沒有暴露的 那么明顯,從系統的維護角度來說,不需要一個工作有兩個角色的工程師完成,可以提升開發效率。
重頁面交互輕業務邏輯的系統也適合Node來開發,說白了如果Web系統如有一半以上的 工作量都是需要前端同學來完成的話,那還不如把整個系統都交給前端同學來維護。
如果公司的工程師都是全棧工程師能在不同語言之間自由切換,那么也就沒有所為的成本一說了。當然這個仍然要受到公司基礎環境的約束,如運維和中間件產品仍然不會同時開發兩套。
小結
隨著技術的不斷進步我們的開發模式也在一直發生著變化,早期的頁面渲染和業務邏輯全部集中在一起,如ASP、PHP、JSP技術,后來由于業務邏 輯不斷變得復雜,出現了MVC的開發框架,前后端工程師分工也越發清楚。中間也有過前端工程師負責整個渲染層和控制層的實現如Extjs+Ajax的開發 模式,但是由于整個渲染是在瀏覽器端完成的受制于客戶端渲染性能和搜索引擎的收錄頁面的硬缺陷很難成為主流。一直到今天前后端開發模式仍然是后端工程師管 理M和C,而由前端來實現V,開發環境和運行環境是一套,所以開發上的耦合導致溝通和調試成本增加。直到Node的出現緩解了前后端開發上的耦合,但是這 種分離仍然是以增加運行時的維護成本來換取開發時的便利,所以我覺得還不是最佳實踐。
本文給出的解決方案也是想兼顧開發時的便利而同時也不增加運行時的維護成本為出發點,當然每種方案都不是完美的,找到適合才是最重要的,隨著Java中執行JS技術的不斷成熟,我想開發環境和運行環境的分離肯定不久就將實現,前后端開發的耦合度也就最終解決。
作者簡介
許令波 ,2009年畢業加入淘寶,目前負責商品詳情業務和穩定性相關工作,長期關注性能優化領域,參與了淘寶高訪問量Web系統主要的優化項目,著有《深入分析Java Web技術內幕》一書。 @淘寶君山、 http://www.xulingbo.net 、xulingbo0201@163.com可以聯系到我。