電商技術(shù)解密:如何讓用戶快速地打開商品詳情頁?
如何盡量減少用戶的流量,減少客戶端與后臺的交互,讓用戶在APP上有比較好的體驗,這些都是在設(shè)計商詳系統(tǒng)時候需要面臨的挑戰(zhàn)。
今天來跟大家聊聊商詳,商詳是展示商品詳情信息的一個頁面,整個購物流程比較重要的一個部分,承載著網(wǎng)站的絕大部分流量。為了提高轉(zhuǎn)化率構(gòu)成商詳?shù)脑胤浅XS富,有大量的圖片、部分商品還有視頻介紹、有相對靜態(tài)的商詳模板,有實時變化的價格、促銷、庫存。
下面我們先來看下商詳上一共有哪些元素組成?
可以看到商詳上的元素非常多,總結(jié)下來分為這么幾個維度:商品維度(標題、主圖、規(guī)格參數(shù)、商品文描)、分類維度、商家維度、店鋪維度。另外還有一些實時性比較高的:價格、實時促銷、配送地址、庫存、廣告等。
主要面臨的挑戰(zhàn)有:
- 高性能,商詳頁聚合服務(wù)比較多,要保證商詳頁在1-2秒內(nèi)可以打開。
- 靈活性較好,可以快速響應(yīng)頁面變更需求。
- 具有較好的擴展性,當訪問量增加的時候可以隨時進行水平擴展。
- 要能夠做到柔性降級,自帶開關(guān)。某些底層服務(wù)出問題時可以通過開關(guān)進行相應(yīng)降級處理。
針對商詳可以有幾種不同的實現(xiàn)方式,用戶看到的是同一個商詳頁,但背后實現(xiàn)的方式卻多種多樣,下面給大家介紹幾種常見的實現(xiàn)。
第一種實現(xiàn)方式:單機版
整個網(wǎng)站放在一臺機器上,通過幾條SQL分別拿到商詳需要展示的各種信息,聚合成一個大的接口吐出給前端展示。
優(yōu)點:邏輯簡單。靈活性較好,可以快速響應(yīng)頁面變更需求。
缺點:性能比較差,沒有擴展性。
第二種實現(xiàn)方式:緩存銀彈
在第一版的基礎(chǔ)上增加各種維度的緩存。可以將主圖、商詳?shù)腍TML模板放到CDN上,每個商品的聚合信息可以放到cache中,不需要每次請求都通過DB獲取商品數(shù)據(jù)。
優(yōu)點:可以一定程度上提高性能。
缺點:需要解決緩存與DB的數(shù)據(jù)一致性問題,單純增加緩存面臨數(shù)據(jù)實時性不高,底層數(shù)據(jù)已經(jīng)修改,緩存中還不是最新數(shù)據(jù)。若任何底層數(shù)據(jù)變更實時更新緩存則修改工作量較大。另外仍然沒有解決擴展性問題。當請求量過大,或者商品數(shù)據(jù)過多將導(dǎo)致性能變差。
第三種實現(xiàn)方式:分布式服務(wù)化
按照領(lǐng)域進行切分,不同業(yè)務(wù)領(lǐng)域獨立實現(xiàn)分別部署,將商詳依賴的底層業(yè)務(wù)領(lǐng)域分別拆分出來。例如,商品、庫存、促銷、地址等分別進行服務(wù)化。每個子領(lǐng)域的服務(wù)自己保證各自的性能。
優(yōu)點:具有很好的靈活性。當有業(yè)務(wù)需求變化的時候,每個子領(lǐng)域內(nèi)部自行修改,對外部提供的接口協(xié)議不變,對外部無感知。并且具有良好的擴展性,當請求量或者數(shù)據(jù)量比較大的時候,每個子領(lǐng)域都可以分別進行橫向擴展。
缺點:開發(fā)難度變大,由于按照領(lǐng)域進行服務(wù)劃分,往往原來一行SQL可以搞定的事情。現(xiàn)在要涉及到多個領(lǐng)域一起配合來修改,需要協(xié)商接口協(xié)議,各個領(lǐng)域內(nèi)部仍有不少開發(fā)量。
下面我們來說幾個基本的概念,上面提到的服務(wù)到底是什么?
服務(wù):自己自足的、無狀態(tài)的業(yè)務(wù)功能,通過定義良好的標準接口,它接受一個或多個請求,返回一個或多個應(yīng)答。
- 服務(wù)不應(yīng)依賴于其他功能或過程;
- 用于提供服務(wù)的技術(shù),編程語言,不構(gòu)成定義的一部分;
- 服務(wù)體現(xiàn)了業(yè)務(wù)功能,聚焦于流程,服務(wù)的主要目標是體現(xiàn)業(yè)務(wù)功能的“自然”步驟。就服務(wù)起作用的業(yè)務(wù)而言,服務(wù)應(yīng)該代表了一項自足的功能,對應(yīng)著一項真實世界的業(yè)務(wù)活動,業(yè)務(wù)人員應(yīng)該理解服務(wù)干了什么。
接口和契約(技術(shù)層面)
- 一項服務(wù)是一個處理(多個)消息的接口,返回信息,以及/或者改變實體(后端系統(tǒng))的狀態(tài)
- 前置條件、后置條件(安全意識,不信任原則)
- 粗粒度:有助于分離服務(wù)提供者的內(nèi)部數(shù)據(jù)結(jié)構(gòu)和外部接口
- 接口的版本、向后兼容
上面介紹了分布式服務(wù)化的方式來實現(xiàn)商詳?shù)募夹g(shù)架構(gòu),那么這樣是不是就完美了?在實際情況下即使這種架構(gòu)還是有很多不可控的因素會影響整個商詳?shù)男阅?。最重要的一個就是對外部服務(wù)的依賴。如果外部服務(wù)出現(xiàn)抖動那么整個商詳頁也會隨之出現(xiàn)不穩(wěn)定。尤其商詳是個比較大的聚合服務(wù),底層依賴的服務(wù)比較多,任何一個出問題都會受到影響,那么商詳出錯的概率就會比較大。如何解決這個問題呢?
一種方案是要求所有底層服務(wù)各自保證自己的穩(wěn)定性,這需要有比較完善的監(jiān)控體系,能夠快速找到出問題的點,然后進行修正。這種方案屬于比較理想狀態(tài),對外部有強依賴。這需要有一個比較靠譜的團隊,團隊中每個人負責的領(lǐng)域穩(wěn)定性、健壯性都比較高,那么這種方式是比較好的,領(lǐng)域的劃分比較清晰,各自的職責也比較清晰。大家各自把自己的領(lǐng)域做好,那么整個網(wǎng)站的效率都比較高。
這對整個團隊要求比較高,這種團隊是存在的,但是當公司業(yè)務(wù)發(fā)展比較快,團隊人數(shù)增長也比較快的時候,這時候團隊的質(zhì)量就比較難保證了,就會出現(xiàn)某一個領(lǐng)域或者某幾個領(lǐng)域質(zhì)量不是很高,就會導(dǎo)致整個服務(wù)調(diào)用鏈都不穩(wěn)定,對整體網(wǎng)站影響較大。那么出現(xiàn)這種問題時如何解決呢?
互不信任原則
對外部不信任的原則是服務(wù)自我保護最重要的方式,盡量降低外部服務(wù)出問題時對本服務(wù)的影響。對于一個寫服務(wù)來說,一定要校驗外部服務(wù)調(diào)用的所有參數(shù)是否合法,對每一個調(diào)用方分配場景ID記錄調(diào)用來源,并且自己要做冪等去重處理。設(shè)計系統(tǒng)時首先想到對于這個外部調(diào)用一旦失敗該如何處理?是否有相應(yīng)的降級策略?對于不同調(diào)用失敗的場景一定要清晰記錄錯誤信息方便后面調(diào)試跟蹤解決問題。
數(shù)據(jù)閉環(huán)
數(shù)據(jù)閉環(huán)即數(shù)據(jù)的自我管理,或者說是數(shù)據(jù)都在自己系統(tǒng)里維護,不依賴于任何其他系統(tǒng),去依賴化;這樣得到的好處就是別人抖動跟我沒關(guān)系。
- 數(shù)據(jù)異構(gòu):是數(shù)據(jù)閉環(huán)的第一步,將各個依賴系統(tǒng)的數(shù)據(jù)拿過來,按照自己的要求存儲起來;
- 數(shù)據(jù)原子化:數(shù)據(jù)異構(gòu)的數(shù)據(jù)是原子化數(shù)據(jù),這樣未來我們可以對這些數(shù)據(jù)再加工再處理而響應(yīng)變化的需求;
- 數(shù)據(jù)聚合:將多個原子數(shù)據(jù)聚合為一個大JSON數(shù)據(jù),這樣前端展示只需要一次get,當然要考慮系統(tǒng)架構(gòu),比如使用Redis,Redis又是單線程系統(tǒng),我們需要部署更多的Redis來支持更高的并發(fā),另外存儲的值要盡可能的?。?/li>
- 數(shù)據(jù)維度化:對于數(shù)據(jù)應(yīng)該按照維度和作用進行維度化,這樣可以分離存儲,進行更有效的存儲和使用。
下面是一種相對比較簡單的維度的劃分:
- 商品基本信息,標題、擴展屬性、特殊屬性、圖片、顏色尺碼、規(guī)格參數(shù)等;
- 商品介紹信息,商品維度商家模板、商品介紹等;
- 非商品維度其他信息,分類信息、商家信息、店鋪信息、店鋪頭、品牌信息等;
- 商品維度其他信息(異步加載),價格、促銷、配送至、廣告詞、推薦配件、最佳組合等。
降級開關(guān)
當?shù)讓酉到y(tǒng)出現(xiàn)問題時候要能夠做到通過開關(guān)的配置屏蔽底層系統(tǒng)的波動對商詳?shù)挠绊懀绠數(shù)讓拥膸齑嫦到y(tǒng)出現(xiàn)問題時可以通過開關(guān)進行配置商詳屏蔽調(diào)用庫存接口,默認所有商品有庫存,這樣庫存數(shù)量可能不是最準確的,但至少可以保證用戶正常瀏覽商詳頁不至于由于底層系統(tǒng)的波動導(dǎo)致整個商詳頁面打不開。在系統(tǒng)設(shè)計時候要盡可能的多預(yù)留降級開關(guān),能降級的地方都要做好降級的準備,只有這樣才能保證商詳?shù)母呖捎谩?/p>
異步并發(fā)
假設(shè)一個讀服務(wù)是需要如下數(shù)據(jù):
- 數(shù)據(jù)A ?10ms
- 數(shù)據(jù)B ?15ms
- 數(shù)據(jù)C ? 20ms
- 數(shù)據(jù)D ? 5ms
- 數(shù)據(jù)E ? 10ms
那么如果串行獲取那么需要:60ms;
而如果數(shù)據(jù)C依賴數(shù)據(jù)A和數(shù)據(jù)B、數(shù)據(jù)D誰也不依賴、數(shù)據(jù)E依賴數(shù)據(jù)C;那么我們可以這樣子來獲取數(shù)據(jù):
那么如果并發(fā)化獲取那么需要:30ms;能提升一倍的性能。
假設(shè)數(shù)據(jù)E還依賴數(shù)據(jù)F(5ms),而數(shù)據(jù)F是在數(shù)據(jù)E服務(wù)中獲取的,此時就可以考慮在此服務(wù)中在取數(shù)據(jù)A/B/D時預(yù)取數(shù)據(jù)F,那么整體性能就變?yōu)榱耍?5ms。
上面我們聊了聊關(guān)于商詳?shù)牟糠旨夹g(shù)實現(xiàn)方案,下期將跟大家聊聊電商的搶購系統(tǒng)的哪些事兒,敬請期待!
本文由 @Nicole 原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理。未經(jīng)許可,禁止轉(zhuǎn)載。
不明覺厲
筆者的架構(gòu)思維和對系統(tǒng)的風(fēng)險意識很好
真的是好文章。還看了作者其他的寫庫存的什么之類的,特別好。
首先聲明下,我是個菜雞。然后我有個問題,大神你舉的并發(fā)例子,我得出的怎是45s … 還有E依賴F的話,預(yù)加載可以,但是怎么會減少響應(yīng)時間,我怎么理解成時間不會變~ (先在這問問,我去找個技術(shù)同學(xué)問問)
好文,這才是干貨。哪天把一些底層的服務(wù)也講講唄,比如價格,比如庫存
會講的
轉(zhuǎn)給我們技術(shù)同事看了。