vivo 商城前端架構升級—前後端分離篇

本文主要以 vivo 商城項目的前後端分離經驗,總結前後端分離思路,整理前後端分離方案,以及分離過程中遇到的問題及解決方案。

一、前言

vivo官方商城在2015年創建網上商城,開闢網絡銷售渠道,幾年來日活和銷售額持續增長,極大的助力了vivo手機的銷量。

而隨着業務版本迭代越來越快,業務內容逐漸增多,前後端不分離模式的弊端也逐漸顯露出來,迭代效率無法跟上逐步增長的業務需求,多端擴展成本高。

爲此,我們在2019年開始進行商城項目的架構升級,進行前後端分離,前端技術升級,接口規範化,以便應對未來更多的業務挑戰。

二、背景

架構升級,第一步面臨的問題便是前後端分離,前後端不分離的痛點已經無需贅述,既影響開發效率,又影響開發體驗,但商城仍然處於業務高速發展時期,不能因爲技術重構而停下業務版本的迭代。

 因此業務版本迭代必須要和前後端分離同時進行,那怎麼才能做到雙線並行,魚和熊掌兼得呢?方案要如何設計?如何應對技術升級帶來的風險和不可控因素呢?

讓我們帶着這些問題來看看vivo商城是如何一步步實現前後端分離。

三、前後端分離

1、基本思路

先分析我們的業務模塊,是標準的樹形結構,每個功能模塊包含若干子模塊,每個子模塊又可以包含若干更小的子模塊,每個子模塊對應的頁面地址頁類似於麪包屑,形成層級包含關係,並且與功能模塊的包含層級一一對應,如下圖:

那如果我們能控制某個模塊的頁面請求,讓它返回分離之後的新頁面,別的請求還訪問老頁面,豈不是就能逐個功能模塊進行分離?嗯,理論上是可行的。

比如以訂單模塊爲例,我們可以攔截訂單相關頁面的請求,使得訂單頁面的請求訪問新的資源,其他頁面請求還訪問老的資源,如下圖:

 

2、逐步分離方案

那麼問題來了,如何實現按訪問路徑去請求不同資源?商城目前的頁面請求和接口請求都是通過 Nginx來做統一的門戶入口,我們能否通過Nginx區分頁面請求路徑,從而達到路由控制的目的?

通過學習研究Nginx配置,發現 Nginx路由匹配有這樣一條特性:

location 匹配首先檢查使用前綴字符定義的 location,選擇最長匹配的項並記錄下來,如果沒有匹配的正則 location 和精確匹配的 location,則使用前面記錄的最長匹配前綴字符 location。

這條信息非常重要,Nginx 的 location 匹配會採用最長的匹配路徑,因爲我們的頁面路徑層級結構跟功能模塊的層級結構是對應的,那我們 location匹配的路徑越長,匹配的功能模塊的粒度就越細,匹配的相應頁面就越精確

比如個人中心(路徑爲/my)下包含訂單相關模塊(路徑爲/my/order),根據Nginx最長匹配原則,就可以通過控制匹配路徑長度,來控制要分離的模塊的大小,比如通過攔截/my/order來攔截所有的訂單相關頁面。、

location /my/order {
  # 匹配所有以/my/order開頭的請求,其他請求不會被攔截,如/my/coupon則不會被攔截
  # 如訂單列表頁面 https://shop.vivo.com.cn/my/order/list 會被攔截
  # 將匹配到的頁面請求轉發到新的靜態資源服務器
  proxy_pass http://new-download;
}

同理,個人中心下的評價模塊下面的頁面路徑都以/my/remark開頭,那可以通過增加配置 location /my/remark {} 來攔截評價模塊。當個人中心下面的子模塊都分離完畢,便可以通過縮短匹配路徑來擴大匹配範圍。

location /my {
  # 匹配所有以/my開頭的請求,即個人中心的所有頁面都被攔截
  # 如個人中心首頁 https://shop.vivo.com.cn/my 會被攔截
  # 將匹配到的頁面請求轉發到新的靜態資源服務器
  proxy_pass http://new-download;
}

當所有的模塊逐步完成了分離,就可以直接攔截根路徑,將所有的頁面請求都取新的靜態資源。

3、雙線並行

技術是服務於業務的,而技術的更迭演進又可以爲業務帶來提升,業務版本在高速迭代,猶如奮力爬升的航天飛機,而利用上述方案,便可以爲飛行中的飛機更換零件甚至發動機,在業務版本迭代的同時逐步進行模塊重構,業務是按版本逐步迭代的,但每次迭代一般不會涉及太多模塊,而是重點針對其中一到兩個模塊進行迭代或者修改,當某次業務版本涉及某個模塊時,我們便可以對這個模塊進行分離,在分離的同時進行業務版本內容的開發,即完成了業務功能開發,又完成了模塊的分離重構,而測試同學只需要測試一次,提高了版本迭代和測試效率。

當然,業務版本一般都是對一些通用模塊的迭代,比如商品,結算,購物車等模塊,總有一些比較穩定或者生僻的模塊很長一段時間甚至一兩年內都不會有大的變動,針對這種情況,就需要單獨的版本進行迭代,好在這些模塊並不算多,業務也相對比較穩定。

4、質量保證,風險規避

在一般的業務迭代中,只需要對某些模塊代碼進行修改,適配,或者補充,整個模塊完全重構,無疑會增加額外的開發和測試工作量,而更多的變動和修改帶來的是更多的風險和不可控因素,那怎麼保證重構質量呢?

同時,業務版本策劃可能只涉及此次版本業務內容,不涉及該模塊的歷史功能,那測試該以什麼參考標準來測試這些歷史功能呢,如何能保證測試覆蓋率,確保所有的業務場景都能被覆蓋到呢?

關於參考標準,線上標準就是最好的標準。現在網頁都提供了http和https兩種訪問方式,用戶訪問的內容是一樣的,在服務器配置也基本上是一樣的,將https的配置改爲新的配置,而http還保持不變,當用https的形式就可以訪問到最新的頁面,而用http形式訪問的還是老頁面,當然,這兩個頁面是可以同時訪問的,因此我們可以進行新舊頁面之間的對比,確保分離前後頁面的一致性。

server {
  listen       80;
  server_name  shop.vivo.com.cn;

  # 老的配置不變
  ...
}

server {
  listen       443;
  server_name  shop.vivo.com.cn;

  # 分離模塊配置
  location /my {
    proxy_pass http://new-download;
  }
}

爲了保證測試覆蓋率,我們引入了代碼覆蓋率檢查工具,精確檢測某一行代碼是否被測試用例覆蓋。通過代碼覆蓋率報告,我們能很清晰的看出哪些代碼被執行了,哪些分支沒有被執行到,爲什麼沒有被執行到,基於這些反饋對測試用例做調整和補充,確保全面的測試覆蓋。

5、遇到的問題

(1)上線部署順序

上線過程主要有三個部分,分別是服務端接口發佈,前端靜態資源發佈,Nginx修改,這三個操作是有前後依賴關係的,如果順序錯了,那就會造成線上事故,因此必須嚴格遵守以下發布順序:

  • 服務端接口發佈

服務端接口是向前兼容的,在分離過程中並不是直接在老接口上修改,而是新開了接口,保證在發佈期間新老接口都是可以調用的。

  • 前端靜態資源發佈

前端頁面依賴於服務端接口,因此必須確保服務端接口已經發布完畢纔可以發前端頁面,否則會出現接口404的問題。

  • Nginx配置修改

這一步要放到最後,如果Nginx在前端靜態資源發佈之前就進行了修改,那用戶訪問頁面時就會出現頁面404的情況。

(2)容災措施

當版本上線出現問題時,如何能快速回退,且不對用戶造成影響?因爲我們是直接攔截用戶請求並重定向到了新的靜態資源服務器,那如果出現線上問題,只需要將此部分的攔截配置關閉,就可以達到快速回退的目的。而服務端接口是向前兼容的,因此無需後退。

四、結果

根據這個方案,我們經過一年時間的逐步迭代,迭代8個版本,終於完成wap端的前後端分離,可以讓專業的人做專業的事。現在回過頭來看看,這次技術升級我們到底解決了什麼難題,而它又爲我們帶來了什麼提升和正向作用呢?

  • 純前端業務上線發佈速度提升10+倍
  • 釋放研發人力,專業的人做專業的事,開發效率最高提升1倍
  • 打好native化、多端渠道拓展基礎
  • 積累技術經驗、賦能更多業務

五、總結

整個前後端分離過程漫長而曲折,在這個過程中我們面臨的最大問題就是如何在人力成本,業務需求和技術升級之間取得一個平衡點,這對我們來說是很有挑戰性的一個難題,很多時候技術問題都可以找到參考和解決方案,但如何能在複雜的人力,資源,版本,技術積累情況下制定技術方案,兼顧各方,去主動推動解決問題,提前識別和規避風險纔是對我們真正的考驗。


作者:vivo官網商城前端團隊

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