前后端分離 - 為什么用Node.js搭建中間層


轉自: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.

前后端職責清晰了

后端 前端
  • 提供數據
  • 處理業務邏輯
  • Server-side MVC架構
  • 代碼跑在服務器上
  • 接收數據,返回數據
  • 處理渲染邏輯
  • Client-side MV* 架構
  • 代碼跑在瀏覽器上

 問題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
  • 服務層
  • 提供數據接口
  • 維持數據穩定
  • 封裝業務邏輯
  • 跑在服務上的JS
  • 轉發數據,串接服務
  • 路由設計,控制邏輯
  • 渲染頁面,體驗優化
  • 更多的可能
  • 跑在瀏覽器上的JS
  • CSS、JS加載與運行
  • DOM操作
  • 任何的前端框架與工具
  • 共用模版、路由

職責清晰的架構 + 前端范圍的擴展 = 更多的可能

 

實際示例1:淘寶首頁優化 

需求

  • 靜態資料展示,方便運營管理
  • 更好的承載密集且龐大的流量

解決方案

  • 頁面緩存與定時刷新,返回緩存資料
  • NodeJS產出靜態頁面到CDN,定時刷新

實際示例2:淘寶詳情頁優化 

需求

  • 單日四億PV,頁面數據來自各個不同接口
  • 為了不影響體驗,先產生頁面框架后再發起多個異步請求取數據更新頁面。這些多出來的請求帶來的影響不小,尤其在無線端

解決方案

在NodeJS端使用Bigpiper技術,合並請求,降低負擔,分批輸出,不影響體驗。

其他優化:

頁面渲染優化

  • 前后端共享模版
  • 首屏服務器渲染
  • 次屏瀏覽器渲染
  • 局部刷新瀏覽器渲染

單頁面應用優化

  • 前后端共享路由與模版
  • 前端換頁,瀏覽器端渲染
  • 直接輸入網址,服務器渲染
  • SEO問題迎刃而解

可靠性優化
單元測試,頁面測試,回歸測試,持續集成。

接口性能優化
拆分大接口為獨立小接口,並發請求。串行 => 並行,大幅縮短請求時間。

部署優化
一台NodeJS對多台JAVA服務器,合理的分配服務器帶來最大的產出。

 

優化時秉承的思想:接口服務化   代碼模塊化   功能組件化


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM