商品詳情系統是一個展示商品基本信息、參數等詳情的系統,是商品購買的入口。它是電商平台中訪問量最大的系統之一,蘇寧易購大促期間PV量和UV量很大,這么大的訪問量對系統的並發能力要求高。在業務上它與周邊系統的關系是高耦合。依賴商品詳情系統的的系統特別多,比如:促銷系統、推薦系統、大聚惠、等眾多營銷系統、還有主數據系統、購物車、收藏夾等,業務復雜度高對系統設計提出更多的要求。
1.重點在於數據展示
2.頁面信息豐富,如:商品詳情、商家列表、推薦、排行榜等
3.部分數據時效要求高,如:價格、庫存等
4. 業務上依賴的系統多
展示
產品上需要設計好頁面區分展示的內容
技術上主要是頁面緩存設計、前端頁面模版和JAVA程序的解耦
數據處理
數據全部來源於其它系統,在數據上分為:
基本數據,外部系統傳過來直接就可以使用的數據
聚合數據,需要加工才能使用的數據
服務依賴
通過MQ解耦,異構數據
解決好以上三個問題就解決了此系統核心問題。
商品詳情系統在設計上分成前、中、后三層結構
1. 前台負責展示,做為VIEW層不處理業務邏輯,負責渲染。
2. 中台負責業務邏輯處理,提供數據給前台,同時還會對外部系統提供服務
3. 后台負責主數據管理,做為數據管理層處理商品主數據、參數、品牌、供應商等,同時部分內容開放給運營進行維護、管理和異常處理等。
頁面設計:
1. 動靜分離
JavaScript、CSS統一放到公共的靜態服務器上,完全獨立的子域名,防止臟Cookie問題和動態域名中無用Cookie問題,通過文件版本號解決系統新版和舊版本之間沖突問題。
所有圖片由獨立的分布式圖片系統管理,對原圖進行不同規格的無損裁減和壓縮。
2. 異步加載和懶加載
商品價格、營銷活動信息、庫存等動態數據通過異步加載
非首屏數據做懶加載處理,提高首屏加載時間,比如評價、商品詳情等內容
3. 多級緩存策略
a. 瀏覽器本地緩存
協商緩存,對於某些時效要求較高的資源通過Last-modified控制數據。做到StatusCode=304
強緩存,JS、CSS等靜態資源或者一些頁面碎片偽靜態數據通過Expires、Cache-Control(http1.1支持)設置做到強緩存,在不強制刷新的情況下可以做到200(from cache)
b. CDN緩存
CDN分兩條線有自營CDN和合作商的CDN,圖片、靜態資源與偽靜態數據分
別放在不到的CDN上
c. Varnish緩存
Varnish在設計上負載使用輪詢方式,不使用URL HASH策略,用空間換時間的策略, 從而避免熱數據問題,也支持橫向擴展。
Varnish 緩存和CDN緩存在失效時間錯開,從而避免同時失效回源壓力過大。
d. 精准緩存
精准緩存失效用於促銷活動准時展示的場景,基於Varnish緩存,通過精准控制緩存有效期實現緩存精准失效保證促銷活動准時切換。
組件邏輯設計:
商品詳情系統中的購買按鈕和加入購物車會因商品不同走不同的流程。如:大聚惠商品、定金團商品、預售商品等因促銷方式不同,走不同的業務處理流程。促銷模式變化多端,可能每個月都會有變化,通常的面向接口編程和加上工廠方法或者依賴管理框架Spring也很難做到真正的解耦,雖然這樣做已經符合開閉原則。我們通過觀察者模式很好的解決了這個問題。讓前端的頁面模版和JAVA應用程序之間真正的解耦。
商品數據統一處理設計
商品詳情系統商品主數據通過MQ消息來源於外部系統,比如:商品基本信息、參數、參數模版、品牌、品類等。我們設計時把共性抽出來分成三部分:
- 接受MQ消息並持久化通過Listener
- 解析報文
- 業務處理上簡化為add、update、delete三個動作
- 異常組件以觀察者模式實現,記錄處理失敗的MQ消息並對消息進行截取,並供下次再反向執行(一條MQ消息中會有一到多條參數、品牌,所以這里用截取)
解耦分兩塊,系統交互間的解耦和商品詳情系統組件間的解耦以及業務流程的解耦
系統間的解耦通過SOA服務治理來解決,但是由於業務的特殊性在服務治理和性能以及一些其它因素的權衡中,我們還選擇了一種共享Redis的方式來解決解耦
商品詳情系統組件間解耦以及業務流程的解耦。
1.0時代中規中矩,移動端完全移值PC的做法
我們使用中規中矩的部署方式Varnish+Apache+JBoss。
這種架構在針對中小系統沒有什么問題,但像商品詳情系統這種訪問量巨大的系統會顯的有點吃力。移動端對性能的要求更高。
2.0時代PC和移動端服務分離,移動端服務合並,性能優化
a. 服務分離與服務合並
PC和移動端的服務分離,以前是同一個接口支持多端,現在是每端都有獨立的應用層服務,原子層服務共享。
移動端處理器和內存性能上的限制,采用服務的合並,且移動端用Nginx+Lua。
b. 公共服務
提出了一個公共服務,公共服務用來接受PC、WAP、APP公共的異步請求的服務。
c.分布式文件系統
商品詳情頁在回源過程中壓力很大,基於其不可降級,我們提出了把商品詳情頁做為一個靜態頁放到分布式文件系統,當DB和Redis壓力過大,直接調取分布式文件系統中數據
3.0時代重點優化移動端性能,接口合並顆粒度更細,增加聚合服務層
多端都使用Nginx+Lua,Nginx 的異步非阻塞型事件處理機制資源消耗少,並發能力高。
- 用Nginx+Lua做為整體的接入層
- 在Nginx接入層 加入三層緩存
- 只有聚合信息才會調用服務層,減少依賴關系
- 服務層數據通過Worker推送和刷新緩存,這親服務層完全和DB隔離
- 移動端連接復用、鏈路復用、防劫持SDK開發等
上面介紹了商品詳情系統前、中、后三層邏輯架構以及各層的設計方法,還介紹了部署架構演變,下面是商品詳情系統數據流程結構的
1.0版本:
這個結構有兩個問題:
數據異構結果沒有和前端展示關聯起來,數據變更不能在前端及時展示
還是沒有解決前端接口依賴問題。
2.0版本:
把前端分成了三部分:
基礎信息組件 不需要加工的消息、聚合信息組件(需要組合消息或者計算才能提供服務的)、實時數據組件處理對外部的依賴
數據異構后會以MQ形式通知基礎服務,並會刷新緩存,這種結構后前端與數據層無直接依賴。
回源是緩存中最頭痛的問題,隨着系統業務復雜度的上升,很難從整體上把控各種業務數據在回源時給一個系統帶來的壓力,如果回源處理不端在極端情況下會導致DB壓力瞬間上升,DB不可用或者連接數滿了等問題,會發生以前類似JVM GC回收時的“stop-the-world”問題。我們回源從被動更新緩存數據更改為主動推送緩存數據從根本上解決這問題。
數據變更通過listener推送緩存至varnish
原來PC端、移動端、TV端產品、開發、測試是分中心分部門,為真正做到多端融合,進行組織架構融合,產品、開發、測試合並到一個中心,統一協調。合並后工作效率變高,產品質量提升,進行小團隊做戰。
展示分離是指在結合公司業務特性、產品自身特性以及降耦合指導思想進行PC、WAP、APP端(IOS、ANDROID)、TV端的展示端進行分離處理。
邏輯融合分離是指在原子服務層進行融合共享,從服務單一職責原則出發在不同端分別提供獨立的服務並加上各自特性,做到接口可擴展性和服務隔離。真正做到一包部署多端使用互不影響,在業務可擴展性和可維護性上做到成本最低。
在物理層為了避免多端進行資源競爭、相互干擾進行獨立部署
商品詳情系統數據庫用Mysql,采用主從加讀寫分離結構,注意:主從不在同一個物理機上,也不在同一組路由器中。應用層中業務上對時效性要求高的數據在寫庫中操作,業務上對於時效性要求不高數據在讀庫中操作。主從結構保證在主庫出現故障比如岩機自動切換到從庫。讀庫通過LVS做負載均衡做到高可用。
DalClient組件支持對數據庫的分庫分表,同時支持橫向擴展。
應用層邏輯優先從Reids中獲取業務數據,如果Redis中沒有,再從DB中獲取。Redis采用sharding方案,每個sharding由一個master和一個salve組成,再通過sentinel保證高可用。當master出現不故障,比如網絡跳動,sentinel會自動把salve切換為master,這個切換是毫秒級的。master和salve通過主動和被動兩種方式來同步,做到最終一致性,符合CAP理論演變過的BASE理論。
借鑒JAVA GC中對內存分代思路解決Redis緩存過期產生的驚群現象。