關於大型網站技術演進的思考(十七)--網站靜態化處理—滿足靜態化的前後端分離(9)

夏天的森林發表於2015-03-07

  前後端分離的主題雖然講完了,但是前後端分離的內容並沒有結束,本篇將繼續前後端分離的問題,只不過這次前後端分離的講述將會圍繞著本系列的主題網站靜態化進行。在講本篇主題之前,我需要糾正一下前後端分離主題講述中會讓朋友們產生誤導的地方,這種誤導就是對時下流行的一些前後端分離方案(沒有使用nodejs的前後端分離方案)的評價問題,其實本人任然覺得不管什麼樣的前後端分離方案只要成功被實施,並且產生了良好的效果,那麼它就是一個成功的前後端分離方案,前面我以一種批判的角度講述這些前後端分離方案,並不是想在否定它們,而是出於一種雞蛋裡挑骨頭的較真態度想重新審視這些方案,希望這種審視能讓我們的設計方案變得更加優秀,同時自己也在這個較勁的過程裡得到自身技術能力的提升。其實那些被我批判的技術方案也許在某些特定場景下它就會變的更加優秀,我推崇的技術方案在某些場景下可能就變的蒼白而無力,這種情況很有可能發生,不說別的,我之所以批評前端MVC,其私心就是因為它不符合網站靜態化的處理,如果把前端MVC內容放置在網站靜態化的主題下談論,被批的命運那是必然的。

  網站靜態化技術相對於前後端分離技術的關注度要低的多,如果業界的一些公司因為看了本人的文章能對網站靜態化技術有一種新的認識,從而考慮在自己網站上使用網站靜態化技術,同時也想實現前後端分離技術,那麼新的問題出現了,這兩種技術同時使用會發生矛盾嗎?如果有矛盾,我們到底將如何解決這些矛盾?解決這些矛盾的時候我們是不是可以做好兩者的兼顧,而不會發生其中一方妥協於另一方,最終導致其中一方沒有充分的發揮自己的能力。要解答上面的一系列問題,我首先要探求的就是網站靜態化技術和前後端分離方案裡那些方面會產生矛盾。

  從我前面對網站靜態化技術的闡述,我們知道網站靜態化的技術最佳作用位置應該是服務端而非是瀏覽器端,之所以會這樣是因為網站靜態化技術的技術基礎是動靜分離和快取,這兩個方面如果落到瀏覽器端會碰到很多難以解決的問題,那麼我們要分析下這些難以解決的問題,具體如下:

  瀏覽器之快取問題:瀏覽器也有快取,不過瀏覽器端的快取那就不是指記憶體裡的快取,而是持久化的快取,實際上瀏覽器端的快取非常不可靠,會被很多非技術的因素所限制,例如我們手動刪除快取或者使用無痕模式上網,那麼這些持久化的快取就會失效,使用者再度訪問網站時候都將是第一次訪問這個網站,這就使得很多優秀的快取策略方案在瀏覽器端實施效果大打折扣。

  瀏覽器之動靜分離問題:網站靜態化技術裡一個重要的手段就是如何設計動靜分離策略,純粹的靜態內容這個沒啥好說的,但是動態的內容在一定的條件(例如:時間,一些業務屬性例如商戶屬性)下是可以轉化為靜態內容,這些內容如果能被有效快取,對網站效能提升是不可估量的,而且這種動靜轉化的策略也可以減少業務伺服器上處理不必要的請求,從而減輕業務伺服器的壓力,達到提升後臺核心業務服務端的負載壓力。但是如果我們使用前端MVC框架,一股腦子把很多服務端功能往前端遷移,那麼這種動靜處理手段就很難做,而且很多場景基本上是無法應用了。

  因此我認為前後端分離方案使用nodejs價值更高,因為使用nodejs我們就可以根據網站靜態化技術將需要保留在服務端的功能可以繼續保留在服務端,這樣就能達到二者兼顧的目的。但是如果我們認為把nodejs引入後,nodejs的目的就是用來做網站整體MVC架構下的C層即控制層,這個思路到底合理不合理呢?這個問題還是很值得玩味的,因此我們需要分析下網站整體MVC架構下的C層即控制層的作用。

  在前面文章裡我曾總結過C層即控制層在MVC框架裡的作用,這個作用分別是:路由、報文格式轉化以及頁面渲染,但是這個作用的總結我是有個前提條件的,那就是以C層即控制層作為前後端溝通介質的前提下。如果前後端分離方案引入後把控制層歸為前端的組成部分,那麼控制層跟前端的結合問題都是人民內部的矛盾,都是比較好解決,但是控制層就僅僅是用來連線前後端一個作用嗎?對於網站架構裡的控制層,有一個不可避免的功能那就是作為後端服務端的安全入口的作用,也就是說控制層是做請求安全檢查和安全監控的地方,而且很多安全校驗還會和業務相關,例如檢查報文是否被篡改啊,防釣魚的功能,如果這些功能被前端來承擔,首先不談前端技術人員會不會做這些,但是至少一點問題是會發生的,前端工程師在關心頁面開始同時還要寫服務端的業務邏輯了,不管怎麼說,這些功能遷移到前端總不是太合適。當網站演變為超大型網站後,大型網站往往是很多小中型網站專案的集合體,為了減少網站整體的異構性,我們常常把不同的模組網站的入口整合在一個大型控制層專案下面,這個大型控制層專案一般稱為閘道器專案,它的作用和網路裡的閘道器非常相似。除此之外,還有些網站的控制層非常特別,例如一些做第三方支付的網站,那麼這樣網站專案本身就是個大閘道器,而且這個閘道器很特別,它後臺的服務就是其他銀行的系統,它的路由工作就會變得異常複雜,例如:根據使用者使用銀行的不同,控制層要組裝不同的報文資訊,而這些功能都是屬於控制層,這樣的場景無疑大幅度提升了控制層再和模型層對接的技術難度,而增加的難度問題又和模型層耦合度很高,由此可見,web應用整體的MVC的控制層比我們想象中要複雜的多。

  回到用nodejs替代控制層這個主題,我們來看看實際的場景吧,假如我們的網站控制層相對比較簡單,好了,這時候我們跟領導或老闆說“現在很流行前後端分離,我們專案也使用下前後端分離技術”,領導或老闆一聽可能會為之一振,那麼就會問你”那麼該怎麼做了”,你這時對他說“首先把控制層用nodejs重寫下”,領導或老闆聽到這個回答他會同意你這麼幹嘛?一個不會給網站增加任何新功能,同時不能很直接有效的提升網站的效能,而且執行它還會有很大風險的方案,頭兒們會同意嗎?好了,假如你終於找到合理理由說服頭兒們,那麼如果我們的網站規模已經很大,控制層已經演變成了閘道器專案,控制層本身已經巨複雜了,你敢用nodejs重寫一遍閘道器專案嗎?所以說吧nodejs直接當做控制層,其實實踐起來困難重重,而且nodejs完全承擔控制層,它的效能,它能否很好的運用於叢集開發這都是很難把控的問題。分析到這裡,我們似乎又進入了死衚衕了,那如何來破這個局呢?

  上面的問題只是反映出整個網站MVC裡的控制層其實還有部分功能是和服務端的模型層緊耦合的,因此要解決這個問題就是把傳統的控制層再細分一下,屬於前端的部分劃分給web前端作為web前端的控制層,屬於服務端的部分任然留給服務端,這麼拆分後,當我們引入了以nodejs為基礎的前後端分離方案,服務端的控制層改造無非就是去掉頁面路由,頁面渲染,再修改下返回資料格式即可,因為不用修改服務端的業務程式碼,其代價是很低的,頭兒們也很容易接受這樣的方案,並支援我們大膽去嘗試新技術。

  服務端網站靜態化技術SSI和ESI,主要是根據動靜分離策略把網頁不會經常變化的模板進行快取,然後在靜態資源伺服器位置整合動靜資源,如果我們使用nodejs只是簡單替換原來的控制層,那麼這些策略其實還是有問題的,那麼怎樣做可以讓nodejs相容SSI和ESI了?這裡我列舉個實際的案例,nodejs有一個模板語言叫做jade,nodejs裡還有個技術叫做handlebarsjs,其中handlebarsjs和struts的標籤類似,它可以處理一些簡單的業務邏輯,我們開發時候使用jade編寫頁面的模板,使用handlebarsjs讓動態資料和模板進行整合,專案釋出時候,使用像grunt這樣的專案管理工具編譯專案,jade檔案變成html檔案,而handlebarsjs則會轉化為javascript程式碼,這樣我們就可以把生成的html檔案在服務端進行有效快取,而handlebars生成的javascript檔案負責整合動靜資料,這樣nodejs就可以達到相容SSI和ESI的作用了。

  不過引入nodejs會讓網站處理請求的過程裡增加一個環節,這樣可能會導致部分效能的損失,但是我上面的例項卻能有另外的方式規避這個問題,因為nodejs的程式碼是用javascript語言編寫的,那麼這個程式碼是可以執行在瀏覽器上的,那麼這就會產生了一個處理手法,那就是我們在生產部署時候其實不需要部署nodejs的,我們把靜態模板就快取在服務端或者推送到CDN上,然後handlebarsjs生成的js程式碼就讓它傳送到瀏覽器端,因為這個js程式碼生成後基本不會變化,瀏覽器可以快取它,當然CDN或靜態資源伺服器也可以快取它,其實它在瀏覽器執行時候變化無非就是獲取一次服務端資料而已。這麼一來,生產上的web前端又轉變成了前端MVC的形式,還把動靜整合的事情交由了瀏覽器來完成,這不僅是兼顧的網站靜態化要求,還讓動靜整合推到了更加靠前的瀏覽器端,這不是達到了一個雙贏的效果了嘛。

  相關文件:

  關於大型網站技術演進的思考(一)--儲存的瓶頸(1)
  關於大型網站技術演進的思考(二)--儲存的瓶頸(2)
  關於大型網站技術演進的思考(三)--儲存的瓶頸(3)
  關於大型網站技術演進的思考(四)--儲存的瓶頸(4)
  關於大型網站技術演進的思考(五)--儲存的瓶頸(5)
  關於大型網站技術演進的思考(六)--儲存的瓶頸(6)
  關於大型網站技術演進的思考(七)--儲存的瓶頸(7)
  關於大型網站技術演進的思考(八)--儲存的瓶頸終篇(8)
  關於大型網站技術演進的思考(九)--網站靜態化處理--總述(1)
  關於大型網站技術演進的思考(十)--網站靜態化處理—動靜整合方案(2)
  關於大型網站技術演進的思考(十一)--網站靜態化處理—動靜分離策略(3)
  關於大型網站技術演進的思考(十二)--網站靜態化處理—快取(4)
  關於大型網站技術演進的思考(十三)--網站靜態化處理—CSI(5)
  關於大型網站技術演進的思考(十四)--網站靜態化處理—前後端分離—上(6)
  關於大型網站技術演進的思考(十五)--網站靜態化處理—前後端分離—中(7)
  關於大型網站技術演進的思考(十六)--網站靜態化處理—前後端分離—下(8)
  關於大型網站技術演進的思考(十七)--網站靜態化處理—滿足靜態化的前後端分離(9)
  關於大型網站技術演進的思考(十八)--網站靜態化處理—反向代理(10)
  關於大型網站技術演進的思考(十九)--網站靜態化處理—web前端優化—上(11)
  關於大型網站技術演進的思考(二十)--網站靜態化處理—web前端優化—中(12)
  關於大型網站技術演進的思考(二十一)--網站靜態化處理—web前端優化—下【終篇】(13)

相關文章