京東購物車如何提升30%性能

本文主要介紹在業務複雜化背景下,京東零售購物車團隊努力踐行工匠精神,通過全異步化改造提升系統性能、提升用戶體驗。通過本文,讀者可以瞭解購物車中臺進行全異步化改造的總體方案,以及方案落地過程中遇到的問題及解決方法,讀者可重點關注文中提到的多分頁並行後,分頁精細控制及底層RPC異常信息問題。



一、背景


購物車面臨的挑戰:
1)新業務 :隨着業務形態的豐富,購物車在不斷支持各種新業務,依賴的外部接口也隨之增加;
2)下沉 :一些前端調用的接口下沉到購物車中臺;
3)前置 :結算流程很多業務前置到購物車中,如優惠券、京豆;
4)擴容 :爲改善用戶體驗購物車可容納的商品數量在不斷增長;
這些導致購物車依賴的RPC接口數量及分頁調用次數都在不斷增加。購物車作爲交易流程開端,本身流量較大,在業務複雜化的背景下,如何提高性能保證用戶體驗,成爲購物車面臨的較大挑戰。


二、全異步化改造方案


通過增加服務器資源雖然能在一定程度上解決問題,但會帶來較大的成本開銷,也與工匠精神相悖。能否通過技術手段提升性能呢?通過分析,異步化改造成爲解決這一問題的有效手段。

1)不同RPC並行
購物車依賴接口達幾十個,各接口間存在複雜依賴關係。必須先梳理各接口間依賴,識別哪些可以並行。然後將原有代碼拆分爲兩部分:RPC異步請求和結果處理,按照依賴關係,讓RPC最大限度並行執行,減少在結果處理階段異步響應等待時間,從而達到提升性能的目的。
2)批量接口多分頁並行
購物車依賴接口多爲批量接口,且單次調用有數據量限制,需將數據拆分爲多個分頁調用。那麼多個分頁間也可以並行,改造中封裝了異步分頁工具,使業務層對分頁邏輯無感知,異步工具自動將超過接口上限的數據拆分爲多個分頁並行調用,提升單接口響應速度。
3)底層採用JSF異步調用
異步調用基於京東RPC框架JSF,推薦使用1.7.5以後版本,支持CompletableFuture。


三、問題及解決


異步化改造的總體方案並不複雜,但是在實際落地過程中,遇到了很多細節問題:

1)異常重試需精細化
同步調用時,如果超時會重試調用。改爲異步後重試會失效,因爲在調用時一般不會報錯,需要在結果處理階段獲取異步響應超時後,再進行重試。
另外,多分頁並行時,當某一頁請求超時後,應該只重試出錯的分頁。底層對分頁調用進行了封裝,上層業務代碼在獲取數據時無法感知是哪一頁超時,所以必須在異步調用時將現場信息保存在包裝類中,一起返回給業務層,在Get數據超時後,單獨重試出錯的分頁。
發生異常時,並不是所有情況都需要重試,當遇到限流等異常時,不能進行重試。底層工具需要自動過濾限流異常,當然也支持自定義規則。
2)異步RPC監控更復雜
底層RPC耗時監控需要拆分爲兩部分,在分頁調用時記爲開始時間,在異步結果到達後,記爲結束時間。如果調用異常或Get超時,需要標記本次調用失敗。對於重試同樣需要記錄調用耗時,且正常調用與重試調用需分開記錄。
除了需要監控RPC耗時外,還需要監控結果處理階段Get等待時長,這個時間纔是真正對應用性能有影響的時間。由於底層是分頁調用,所以業務調用次數和底層RPC調用次數並不相同。
3)分頁異步結果不能合併,否則無法獲取異常Provider信息
底層異步調用結果,必須通過包裝類原樣返回給上層,除了上邊提到的需要單分頁重試外,另一個原因是必須保留異步結果,在分頁超時後才能輸出超時的Provider信息。這是由於Provider信息依賴JSF框架的JSFCompletableFuture,如果在底層合併結果,會導致信息丟失。
4)每頁超時時間需單獨控制
分頁調用過程如上圖所示,在結果處理時,每頁Get超時時間需要單獨控制,因爲獲取結果是順序進行,獲取後邊的分頁時,前邊分頁等待的時間也應計算在內,以保證整個獲取結果的時間不超過單個分頁的最大超時時間。 計算公式如下:
超時=RPC超時時間 > (當前時間-異步調用開始時間) ? RPC超時時間 – (當前時間-異步調用開始時間) : 0
5)分頁均衡
爲避免最後一頁數據過少造成數據傾斜,需要將請求數據均分到每一頁,以最大限度提高整個請求的性能。


四、收益


改造完成後購物車核心接口耗時減少30%,保證用戶體驗,節省大量服務器資源。 後續增加新的RPC接口時,只要處在調用拓撲的非關鍵路徑上,對購物車性能沒有太大影響。 另外,容量增加時除少數不能分頁調用的接口外,對性能影響已經比較小。

-end-

本文分享自微信公衆號 - 京東雲開發者(JDT_Developers)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

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