轉自:https://2014.jsconfchina.com/slides/herman-taobaoweb/index.html#/ https://mp.weixin.qq.com/s/KzumZwo3ITX0TZvTIhq4vg
為什么用Node.js搭建中間層
什么是中間層
在翻看很多技術文章時,大家都提到“中間層”,在很多大型企業中,Node確實承擔了“中間層”的角色,那么,Node為什么被廣泛的應用在“中間層”呢?
要回答這個問題,先來陳述下什么是中間層。
通常我們把Web領域分為客戶端和服務端,也就是前端和后端,這里的后端就包含了網關,靜態資源,接口,緩存,數據庫等。而中間層呢,就是在后端這里再抽離一層出來,在業務上處理和客戶端銜接更緊密的部分,比如頁面渲染(SSR),數據聚合,接口轉發等等。
以SSR來說,在服務端將頁面渲染好,可以加快用戶的首屏加載速度,避免請求時白屏,還有利於網站做SEO,他的好處是比較好理解的。那么對於數據的聚合,接口轉發來說,這樣做有什么意義呢?
用Node的4點意義
業務驅動
Node有個突出的優勢,他的開發者可以是前端。
前端對於頁面所需要的數據有更好的理解,每個頁面要用到哪些接口,每個接口要用到哪些字段前端是最清楚的。再加上實際業務開發中,前端頁面需求經常會發生變化,需要修改字段或者數據結構,所以對接頁面的這部分接口由前端直接開發非常合適,可以顯著的減少溝通成本。
架構需要
面向用戶的接口由Node中間層負責以后,真正的服務端可以專注於提供基於領域模型的對內接口,做微服務。
比如可以基於Goods模型,提供所有商品相關的接口;基於Users模型,提供所有用戶相關接口。當一個接口需要商品+用戶信息時,由Node分別查詢組裝。從整體業務代碼維護角度來說,變得更容易,不會因為業務發展使得每個接口都異常繁雜。
性能滿足
如果僅僅是架構層面的需求,需要有一個中間層來沉淀業務,那用Java,PHP也可以做到,為什么說Node更適合做呢?
因為Node天生異步!
眾所周知,js是一門單線程語言,所以Node在實現的時候,需要借助libuv來實現異步。
如圖所示,libuv為Node提供了線程池,事件池,異步I/O等能力。正是因為其中網絡I/O的異步能力,可以讓Node做接口聚合時,能夠更高效的異步並發處理。
成本較低
Node使用js開發,只需要學習簡單的api,前端開發者就可以無障礙使用,學習成本很低。
而且,Node具有活躍的社區和豐富的模塊池,擁有很多現成的功能實現。框架方面,也有成熟的koa,express等基本框架和egg等二次封裝框架,可根據需求選擇上手也比較方便。
案例:淘寶前后端分離實踐
為什么要前后端分離
- 關注點分離
- 職責分離
- 對的人做對的事
- 更好的共建模式
- 快速的反應變化
階段一:后端MVC
VIEW層的兩種維護方式
1.前端寫Demo,后端套頁面
問題:后端需要寫HTML,且前端仍然需要確認后端寫的HTML。
2.前端寫View層,后端只管數據
問題:前端需要熟悉后端語言,且前端需要了解后端架構。
問題1:前端代碼越來越復雜
- 無法統一協作模式,代碼充滿了約定
- JS跟CSS,依賴於后段產出的HTML
- 有的數據來自AJAX,有的數據印在DOM上
- 有的業務邏輯在前端,有的在Model層,更多的是在View層
問題2:前后端依舊高度耦合
- 前端依賴服務端開發環境
- 在服務端View層高度耦合
- 溝通成本高
- 職責不清晰
問題3:無法良好的支持跨終端
- 業務邏輯散落在應用中
- 渲染邏輯強依賴后端頁面
- 只能用responsive design硬來
問題4:高度耦合的前后端分工
- 溝通成本上升
- 維護成本上升
- 無法正確且快速的響應變化
- 代碼的腐爛只是遲早的問題
階段二:CLIENT-SIDE MV*
接口分離, 后端提供數據, 前端自己搞
- MODEL層 - JAVASCRIPT OBJECT
- VIEW層 - JAVASCRIPT TEMPLATE
業界滿坑滿谷的優秀方案:Backbone, EmberJS, KnockoutJS, AngularJS, React, etc.
前后端職責清晰了
后端 | 前端 |
---|---|
|
|
問題1:各層職責重疊,並且各玩各的
- Client-side Model是Server-side Model 的加工
- Client-side View跟Server-side是不同層次的東西
- Client-side的Controller跟Sever-side的Controller各搞各的
- Client-side的Route在Server-side可能沒有
問題2:性能問題
- 渲染,取值都在客戶端進行,有性能的問題
- 需要等待資源到齊才能進行,會有短暫白屏與閃動
- 在移動設備低速網路的體驗奇差無比
問題3:重用問題
- 模版無法重用,造成維護上的麻煩與不一致
- 邏輯無法重用,前端的校驗后端仍須在做一次
- 路由無法重用,前端的路由在后端未必存在
問題4:跨終端問題
- 業務太靠前,導致不同端重復實現
- 邏輯太靠前,造成維護上的不易
問題5:SEO問題
- 渲染都在客戶端,模版無法重用,SEO實現麻煩
階段三:重新定義前后端
是依照工作職責來划分的前后端,還是依照硬體環境划分的前后端?
傳統認知的前后端(按硬體環境划分)
重新定義的前后端(按工作指責划分)
在服務器(JAVA)與瀏覽器(JS)的中間架了一個中間層(NODEJS)
WHY NODEJS
- 前端熟悉的語言,學習成本低
- 都是JS,可以前后端復用
- 體質適合:事件驅動、非阻塞I/O
- 適合IO密集型業務
- 執行速度也不差
指責划分
后端 |
前端 |
|
---|---|---|
服務器 | 瀏覽器 | |
JAVA | NodeJS | JS + HTML + CSS |
|
|
|
職責清晰的架構 + 前端范圍的擴展 = 更多的可能
實際示例1:淘寶首頁優化
需求
- 靜態資料展示,方便運營管理
- 更好的承載密集且龐大的流量
解決方案
- 頁面緩存與定時刷新,返回緩存資料
- NodeJS產出靜態頁面到CDN,定時刷新
實際示例2:淘寶詳情頁優化
需求
- 單日四億PV,頁面數據來自各個不同接口
- 為了不影響體驗,先產生頁面框架后再發起多個異步請求取數據更新頁面。這些多出來的請求帶來的影響不小,尤其在無線端
解決方案
在NodeJS端使用Bigpiper技術,合並請求,降低負擔,分批輸出,不影響體驗。
其他優化:
頁面渲染優化
- 前后端共享模版
- 首屏服務器渲染
- 次屏瀏覽器渲染
- 局部刷新瀏覽器渲染
單頁面應用優化
- 前后端共享路由與模版
- 前端換頁,瀏覽器端渲染
- 直接輸入網址,服務器渲染
- SEO問題迎刃而解
可靠性優化
單元測試,頁面測試,回歸測試,持續集成。
接口性能優化
拆分大接口為獨立小接口,並發請求。串行 => 並行,大幅縮短請求時間。
部署優化
一台NodeJS對多台JAVA服務器,合理的分配服務器帶來最大的產出。
優化時秉承的思想:接口服務化 代碼模塊化 功能組件化