應用數據靜態化架構高性能單頁Web應用

在電商網站中,單頁Web是非常常見的一種形式,比如首頁、頻道頁、廣告頁等都屬於單頁應用。而這種頁面是由模板+數據組成。傳統的構建方式一般通過靜態化實現。而這種方式的靈活性並不是很好,比如頁面模板部分變更了需要重新全部生成。因此最好能有一種實現方式是可以實時動態渲染,以支持模板的多變性。另外也要考慮好如下幾個問題:

1、動態化模板渲染支持;

2、數據和模板的多版本化:生產版本、灰度版本和預發佈版本;

3、版本回滾問題,假設當前發佈的生產版本出問題瞭如何快速的回滾到上一個版本;

4、異常問題,假設渲染模板時遇到了異常情況(比如獲取Redis出問題了),如何處理;

5、灰度發佈問題,比如切20%量給灰度版本;

6、預發佈問題,目的是在正式環境測試數據和模板的正確性。

 

整體架構

靜態化頁面的方案如下圖所示:


直接將生成的靜態頁推送到相關服務器即可。使用這種方式要考慮文件操作的原子化問題(即從老版本切換到新版本如何做到文件操作原子化)。

 

而動態化方案的整體架構如下圖所示,分爲三大系統:CMS系統、控制系統和前端展示系統。


 

CMS系統

1、在CMS系統可以配置頁面的模板和數據;

1.1、模板動態在CMS系統中維護,即模板不是一個靜態文件,而是存儲在CMS中的一條數據,最終發佈到“發佈數據存儲Redis”中,前端展示系統從Redis中獲取該模板進行渲染,從而前端展示系統更換了模板也不需要重啓,純動態維護模板數據;

2、原始數據存儲到“元數據存儲Mysql”中即可,比如頻道頁一般需要:前端訪問的URL、分類、輪播圖、商品樓層數據等;這些數據按照相應的維度存儲在CMS系統中;

3、提供發佈到“發佈數據存儲Redis”的控制,將CMS系統中的原始數據和模板數據組裝成聚合數據(JSON存儲)同步到“發佈數據存儲Redis”,以便前端展示系統獲取進行展示;此處提供三個發佈按鈕:正式版本、灰度版本和預發佈版本。

 

目前存在如下幾個問題:

1、用戶如訪問http://channel.jd.com/fashion.html怎麼定位到對應的聚合數據呢? 我們可以在CMS元數據中定義URL作爲KEY,如果沒有URL,則使用ID作爲KEY,或者自動生成一個URL。

2、多版本如何存儲呢? 使用Redis的Hash結構存儲即可,KEY爲URL(比如http://channel.jd.com/fashion.html),字段按照維度存儲:正式版本使用當前時間戳存儲(這樣前端系統可以根據時間戳排序然後獲取最新的版本)、預發佈版本使用“predeploy”作爲字段,灰度版本使用“abVersion”作爲字段即可,這樣就區分開了多版本。

3、灰度版本如何控制呢?這個通過控制系統的開關來控制如何灰度;

4、如何訪問預發佈版本呢?比如在URL參數總帶上predeploy=true,另外可以限定只有內網可以訪問或者訪問時帶上訪問密碼,比如pwd=absdfedwqdqw。

5、模板變更的歷史數據校驗問題?比如模板變更了,但是使用歷史數據渲染該模板會出現問題,即模板要兼容歷史數據的;此處的方案不存在這個問題,因爲每次存儲時是當時的模板快照,即數據快照和模板快照推送到“發佈數據存儲Redis”中。

 

前端展示系統

1、獲取當前URL,使用URL作爲KEY首先從本機“發佈數據存儲Redis”獲取數據;

2、如果沒有數據或者異常則從主“發佈數據存儲Redis”獲取;

3、如果主“發佈數據存儲Redis”也發生了異常,那麼會直接調用CMS系統暴露的API直接從元數據存儲Mysql中獲取數據進行處理。

 

展示系統的僞代碼

Java代碼  收藏代碼
  1. --1、加載Lua模塊庫  
  2. local template = require("resty.template")  
  3. template.load = function(s) return s end  
  4.    
  5. --2、動態獲取模板  
  6. local myTemplate = "<html>{* title *}</html>"  
  7. --3、動態獲取數據  
  8. local data = {title = "iphone6s"}  
  9.    
  10. --4、渲染模板  
  11. local func = template.compile(myTemplate)  
  12. local content = func(data)  
  13.    
  14. --5、通過ngx API輸出內容  
  15. ngx.say(content)  

即模板和數據都是動態獲取的,然後使用動態獲取的模板和數據進行渲染。

 

此處假設最新版本的模板或數據有問題怎麼辦?這個可以從流程上避免:1、首先進行預發佈版本發佈,測試人員驗證沒問題後;2、接着發佈灰度版本,在灰度時自動去掉CDN功能(即不設置頁面的緩存時間),發佈驗證OK;3、發佈正式版本即可;正式版本發佈的5分鐘內是不設置頁面緩存的,這樣就可以防止發版時遇到問題,但是問題版本已經在CDN上給全部用戶造成問題。當然這個流程很麻煩,可以按照自己的場景進行簡化。

 

控制系統

控制系統用於版本降級和灰度發佈的,當然可以把這個功能放在CMS系統中實現。

版本降級:假設當前線上的版本遇到問題了,想要快速切換回上一個版本,可以使用控制系統實現,選中其中一個歷史版本然後通知給前端展示系統即可,使用URL和當前版本的字段即可,這樣前端展示系統就可以自動切換到選中的那個版本;當問題修復後,再刪除該降級配置即切換回最新版本。

灰度發佈:在控制系統控制哪些URL需要灰度發佈和灰度發佈的比例,同版本降級類似將相關的數據推送到前端展示系統即可,當不想灰度發佈時刪除相關數據即可。

 

數據和模板動態化

我們將數據和模板都進行動態化存儲,這樣可以在CMS進行數據和模板的變更;實現了前端和後端開發人員的分離;前端開發人員進行CMS數據配置和模板開發,而後端開發人員只進行系統的維護。另外因爲模板的動態化存儲,每次發佈新的模板不需要老重啓前端展示系統,後端開發人員更好地得到了解放。

 

模板和數據可以是一對多的關係,即一個模板可以被多個數據使用。假設模板發生變更後,我們可以批量推送模板關聯的數據,首先進行預發佈版本的發佈,測試人員進行驗證,驗證沒問題即可發佈正式版本。

 

多版本機制

我們將數據和模板分爲多版本後,可以實現:

預發佈版本:更容易讓測試人員在實際環境進行驗證;

灰度版本:只需要簡單的開關控制,就可以進行A/B測試;

正式版本:存儲多個歷史正式版本,假設最新的正式版本出現問題,可以非常快速的切換回之前的版本。

 

異常問題

其中一個擔心就是本機從“發佈數據存儲Redis”和主“發佈數據存儲Redis”都掛了,那麼我們直接調用CMS系統暴露的HTTP服務直接從元數據存儲Mysql獲取數據。

 

另外一個擔心是數據和模板獲取到了,但是渲染模板出錯了,比如遇到500、503;解決方案是:使用上一個版本的數據進行渲染。

 

另外還一種問題是數據和模板都沒問題,但是因爲一些疏忽,渲染出來的頁面錯亂了或者有些區域出現了空白;對於這種問題沒有很好的解決方案;可以根據自己的場景定義異常掃描庫,掃描當前版本有異常就發警告給相關人員,並自動降級到上一個版本。

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