電商技術解密:如何讓用戶快速地打開商品詳情頁?

7 評論 28165 瀏覽 209 收藏 12 分鐘

如何盡量減少用戶的流量,減少客戶端與后臺的交互,讓用戶在APP上有比較好的體驗,這些都是在設計商詳系統時候需要面臨的挑戰。

今天來跟大家聊聊商詳,商詳是展示商品詳情信息的一個頁面,整個購物流程比較重要的一個部分,承載著網站的絕大部分流量。為了提高轉化率構成商詳的元素非常豐富,有大量的圖片、部分商品還有視頻介紹、有相對靜態的商詳模板,有實時變化的價格、促銷、庫存。

下面我們先來看下商詳上一共有哪些元素組成?

1

可以看到商詳上的元素非常多,總結下來分為這么幾個維度:商品維度(標題、主圖、規格參數、商品文描)、分類維度、商家維度、店鋪維度。另外還有一些實時性比較高的:價格、實時促銷、配送地址、庫存、廣告等。

主要面臨的挑戰有:

  • 高性能,商詳頁聚合服務比較多,要保證商詳頁在1-2秒內可以打開。
  • 靈活性較好,可以快速響應頁面變更需求。
  • 具有較好的擴展性,當訪問量增加的時候可以隨時進行水平擴展。
  • 要能夠做到柔性降級,自帶開關。某些底層服務出問題時可以通過開關進行相應降級處理。

針對商詳可以有幾種不同的實現方式,用戶看到的是同一個商詳頁,但背后實現的方式卻多種多樣,下面給大家介紹幾種常見的實現。

第一種實現方式:單機版

整個網站放在一臺機器上,通過幾條SQL分別拿到商詳需要展示的各種信息,聚合成一個大的接口吐出給前端展示。

優點:邏輯簡單。靈活性較好,可以快速響應頁面變更需求。

缺點:性能比較差,沒有擴展性。

第二種實現方式:緩存銀彈

在第一版的基礎上增加各種維度的緩存。可以將主圖、商詳的HTML模板放到CDN上,每個商品的聚合信息可以放到cache中,不需要每次請求都通過DB獲取商品數據。

優點:可以一定程度上提高性能。

缺點:需要解決緩存與DB的數據一致性問題,單純增加緩存面臨數據實時性不高,底層數據已經修改,緩存中還不是最新數據。若任何底層數據變更實時更新緩存則修改工作量較大。另外仍然沒有解決擴展性問題。當請求量過大,或者商品數據過多將導致性能變差。

第三種實現方式:分布式服務化

按照領域進行切分,不同業務領域獨立實現分別部署,將商詳依賴的底層業務領域分別拆分出來。例如,商品、庫存、促銷、地址等分別進行服務化。每個子領域的服務自己保證各自的性能。

優點:具有很好的靈活性。當有業務需求變化的時候,每個子領域內部自行修改,對外部提供的接口協議不變,對外部無感知。并且具有良好的擴展性,當請求量或者數據量比較大的時候,每個子領域都可以分別進行橫向擴展。

缺點:開發難度變大,由于按照領域進行服務劃分,往往原來一行SQL可以搞定的事情?,F在要涉及到多個領域一起配合來修改,需要協商接口協議,各個領域內部仍有不少開發量。

下面我們來說幾個基本的概念,上面提到的服務到底是什么?

服務:自己自足的、無狀態的業務功能,通過定義良好的標準接口,它接受一個或多個請求,返回一個或多個應答。

  • 服務不應依賴于其他功能或過程;
  • 用于提供服務的技術,編程語言,不構成定義的一部分;
  • 服務體現了業務功能,聚焦于流程,服務的主要目標是體現業務功能的“自然”步驟。就服務起作用的業務而言,服務應該代表了一項自足的功能,對應著一項真實世界的業務活動,業務人員應該理解服務干了什么。

接口和契約(技術層面)

  • 一項服務是一個處理(多個)消息的接口,返回信息,以及/或者改變實體(后端系統)的狀態
  • 前置條件、后置條件(安全意識,不信任原則)
  • 粗粒度:有助于分離服務提供者的內部數據結構和外部接口
  • 接口的版本、向后兼容

上面介紹了分布式服務化的方式來實現商詳的技術架構,那么這樣是不是就完美了?在實際情況下即使這種架構還是有很多不可控的因素會影響整個商詳的性能。最重要的一個就是對外部服務的依賴。如果外部服務出現抖動那么整個商詳頁也會隨之出現不穩定。尤其商詳是個比較大的聚合服務,底層依賴的服務比較多,任何一個出問題都會受到影響,那么商詳出錯的概率就會比較大。如何解決這個問題呢?

一種方案是要求所有底層服務各自保證自己的穩定性,這需要有比較完善的監控體系,能夠快速找到出問題的點,然后進行修正。這種方案屬于比較理想狀態,對外部有強依賴。這需要有一個比較靠譜的團隊,團隊中每個人負責的領域穩定性、健壯性都比較高,那么這種方式是比較好的,領域的劃分比較清晰,各自的職責也比較清晰。大家各自把自己的領域做好,那么整個網站的效率都比較高。

這對整個團隊要求比較高,這種團隊是存在的,但是當公司業務發展比較快,團隊人數增長也比較快的時候,這時候團隊的質量就比較難保證了,就會出現某一個領域或者某幾個領域質量不是很高,就會導致整個服務調用鏈都不穩定,對整體網站影響較大。那么出現這種問題時如何解決呢?

互不信任原則

對外部不信任的原則是服務自我保護最重要的方式,盡量降低外部服務出問題時對本服務的影響。對于一個寫服務來說,一定要校驗外部服務調用的所有參數是否合法,對每一個調用方分配場景ID記錄調用來源,并且自己要做冪等去重處理。設計系統時首先想到對于這個外部調用一旦失敗該如何處理?是否有相應的降級策略?對于不同調用失敗的場景一定要清晰記錄錯誤信息方便后面調試跟蹤解決問題。

數據閉環

數據閉環即數據的自我管理,或者說是數據都在自己系統里維護,不依賴于任何其他系統,去依賴化;這樣得到的好處就是別人抖動跟我沒關系。

  • 數據異構:是數據閉環的第一步,將各個依賴系統的數據拿過來,按照自己的要求存儲起來;
  • 數據原子化:數據異構的數據是原子化數據,這樣未來我們可以對這些數據再加工再處理而響應變化的需求;
  • 數據聚合:將多個原子數據聚合為一個大JSON數據,這樣前端展示只需要一次get,當然要考慮系統架構,比如使用Redis,Redis又是單線程系統,我們需要部署更多的Redis來支持更高的并發,另外存儲的值要盡可能的小;
  • 數據維度化:對于數據應該按照維度和作用進行維度化,這樣可以分離存儲,進行更有效的存儲和使用。

下面是一種相對比較簡單的維度的劃分:

  1. 商品基本信息,標題、擴展屬性、特殊屬性、圖片、顏色尺碼、規格參數等;
  2. 商品介紹信息,商品維度商家模板、商品介紹等;
  3. 非商品維度其他信息,分類信息、商家信息、店鋪信息、店鋪頭、品牌信息等;
  4. 商品維度其他信息(異步加載),價格、促銷、配送至、廣告詞、推薦配件、最佳組合等。

降級開關

當底層系統出現問題時候要能夠做到通過開關的配置屏蔽底層系統的波動對商詳的影響,例如當底層的庫存系統出現問題時可以通過開關進行配置商詳屏蔽調用庫存接口,默認所有商品有庫存,這樣庫存數量可能不是最準確的,但至少可以保證用戶正常瀏覽商詳頁不至于由于底層系統的波動導致整個商詳頁面打不開。在系統設計時候要盡可能的多預留降級開關,能降級的地方都要做好降級的準備,只有這樣才能保證商詳的高可用。

異步并發

假設一個讀服務是需要如下數據:

  1. 數據A ?10ms
  2. 數據B ?15ms
  3. 數據C ? 20ms
  4. 數據D ? 5ms
  5. 數據E ? 10ms

那么如果串行獲取那么需要:60ms;

而如果數據C依賴數據A和數據B、數據D誰也不依賴、數據E依賴數據C;那么我們可以這樣子來獲取數據:

2

那么如果并發化獲取那么需要:30ms;能提升一倍的性能。

假設數據E還依賴數據F(5ms),而數據F是在數據E服務中獲取的,此時就可以考慮在此服務中在取數據A/B/D時預取數據F,那么整體性能就變為了:25ms。

上面我們聊了聊關于商詳的部分技術實現方案,下期將跟大家聊聊電商的搶購系統的哪些事兒,敬請期待!

 

本文由 @Nicole 原創發布于人人都是產品經理。未經許可,禁止轉載。

更多精彩內容,請關注人人都是產品經理微信公眾號或下載App
評論
評論請登錄
  1. 不明覺厲

    來自廣東 回復
  2. 筆者的架構思維和對系統的風險意識很好

    來自廣東 回復
  3. 真的是好文章。還看了作者其他的寫庫存的什么之類的,特別好。

    來自日本 回復
  4. 首先聲明下,我是個菜雞。然后我有個問題,大神你舉的并發例子,我得出的怎是45s … 還有E依賴F的話,預加載可以,但是怎么會減少響應時間,我怎么理解成時間不會變~ (先在這問問,我去找個技術同學問問)

    來自浙江 回復
  5. 好文,這才是干貨。哪天把一些底層的服務也講講唄,比如價格,比如庫存

    來自上海 回復
    1. 會講的

      來自江蘇 回復
  6. 轉給我們技術同事看了。

    來自廣東 回復