京東手機商品詳情頁技術解密

分類:技術 時間:2017-01-13

作者:陳保安,2011年加入京東,目前主要負責手機京東核心業務(搜索、商品、購物車、結算、收銀臺、我的京東)的后端研發工作。帶領團隊在一線奮戰多年,積累了非常豐富的大促備戰經驗,也見證了核心系統從一分鐘幾千單到幾十萬單的質的蛻變。

京東手機單品頁在每次大促時承載所有流量的入口,它被天然賦予的一個標簽就是抗壓,對系統的穩定性、性能方面要求極其苛刻,另外單品頁本身業務復雜度較高,單品頁有幾十種垂直流程業務,并且展示上都要求個性化的單品頁,加上依賴有50 的基礎服務,稍有抖動,對整體服務質量都會有比較大的影響,因此之前大促也出現過各種問題,不斷打磨,持續優化升級,當前系統架構可支撐接近百萬的QPS瞬時訪問,并且今年雙11表現非常平穩,借此機會一塊和大家做一次分享。

一、先聊聊APP接口開發的特點

1、手機網絡、流量受限

  • 手機單品頁提供給APP的API受限于運營商的網絡,手機的信號時有時無、時好時壞極其不穩定,為了減少客戶端和后端建連握手的過程,因此接口下發內容大而全,涵蓋了頁面上的所有內容,沒辦法像瀏覽器BS的結構可以有大量的ajax請求;

  • API接口依賴了幾十個基礎服務,任何接口的抖動對整體接口性能影響很大,因此必須是并發請求依賴,減少接口抖動疊加的影響;

  • 單品頁有大量的圖片信息,商品主圖、插圖、推薦商品、手機配件商品、排行榜等等圖片信息量比較大,單個圖片的大小對手機流量影響較大,所有下發的圖片采用是webp格式,極大減少網絡傳輸流量。

2、手機不同分辨率、網絡環境、系統版本的適配

  • 不同環境下用戶的體驗存在差異,比如在弱網、低版本、分辨率差的手機會保持最基本的購物車流程,會減少一些增值的體驗;

  • 圖片的展示尺寸也會根據網絡環境、分辨率大小進行適配。

3、APP版本兼容

  • 新業務需求變更盡可能兼容老版本,但有些業務很難兼容老版本,因此系統里面存在很多版本適配的邏輯,增加了系統的復雜度;

  • 客戶端如果出現重大bug并且沒辦法進行hotfix的情況下,需要服務端針對特定版本進行打補丁,也增加代碼復雜度以及后期的維護成本。

因此APP的接口開發邏輯復雜度和后續的維護成本被放大很多。

二、單品頁業務系統架構

這是當前單品頁系統的整體架構圖,其他的核心交易流程,比如購物車、下單等也都基本類似,單品頁系統主要有三個進程:OpenResty、Tracer-Collect、Tomcat,以及包含幾個旁路系統。OpenResty是nginx層的web容器,主要職責是做靜態化和限流防刷,只有經過清洗過的流量才會流轉到tomcat的java進程真正的業務處理,Tracer-Collect進程是通過旁路的方式異步埋點到統一的監控平臺,進行實時的數據分析。

三、核心技術點

1、OpenResty

這個是在今年618之前架構上做的一個變化,主要有以下幾點考慮:

  • 業務需要,業務流量到一定程度,需要把靜態化數據以及限流策略前置,更多把流量擋在前端,減少業務系統壓力;

  • ngx_openresty模塊有效地把Nginx 服務器轉變為一個強大的 Web 應用服務器,在其他0級系統中已經很好驗證了帶來的高可用、高并發的能力。

使用規范上

  • Lua屬于腳本語言,開發相對java語言比較開放,比如方法可以返回多對象,這對長期java開發人員就有很多不適應,在灰度過程中及時發現并進行修復,因此利用lua來滿足特殊需求外,不會進行過多業務邏輯處理;

  • 任何技術上的變動都要極度謹慎,不斷的進行灰度測試,我們是從一臺機器逐步灰度到一個set,再擴散到一個渠道,最后全量,并且具備實時的異常數據埋點能力,及時發現灰度過程中問題,一旦發現問題要有開關能實時降級。

Lua語言對于很多團隊都使用過程中都遇到各種問題,今年雙11的總結會上也有團隊分享大促期間lua死鎖問題,我們這里遇到的一個場景是zk的配置數據同步到lua時一定概率出現死鎖。

原因:lua運行在nginx主線程中,但zk在nginx主線程外啟動新的線程watch,當zk更新時通過這個新線程通知數據更新,這時我們在這個新的線程中直接調用lua代碼,會有概率產生死鎖。

解決方案:在這個新線程中不直接調用lua代碼,而是通過http協議直接進入nginx主線程更新配置數據。

2、數據靜態化

單品頁給APP提供的API重點包含兩個,一個是靜態接口,一個是動態接口數據,這里提到的靜態化重點是針對靜態接口數據,包含商品圖片、基本信息、店鋪商家信息、顏色尺碼、延保…..等,去年雙11期間,由于一些熱點商品訪問量過大,對jimdb集群單個分片的連接數和操作數都非常高,服務壓力過大,整體集群服務性能變差,因此針對此進行了三級熱點的優化:

  • CDN

    眾所周知,CDN本來就是替業務靜態流量扛熱點數據,但是上邊提到后端有很多的適配工作,包括平臺、網絡環境、分辨率尺寸,要知道Android的分辨率五花八門,所以這種邏輯的話CDN很難發揮作用,因此今年針對這個邏輯做了優化,接口下發給APP的數據都是標準數據格式,同時會下發對應的適配規則給APP,由APP根據規則進行動態適配,極大地提升了緩存命中率,另外別忘了還要加上各種開關控制和數據的埋點監控,這也是APP開發的一個重要特征,APP發出去的版本如果出現各種未知情況將會是災難,在618之前版本經過各種灰度最終還是順利上線,在618期間發揮了重要作用,CDN的命中率達到60%以上,大促的0點開始大部分人還是集中在少數的爆款商品上。這是第一層的保護。

  • OpenResty(Nginx Lua)層靜態化

    上邊提到這一層重點還是數據靜態化和防刷,您可能有疑問,CDN已經替擋住了大部分流量,為什么還需要這一層?CDN只是擋住了App的最新版本熱點流量,還有M渠道是通過內網網關過來的,不經過CDN,以及App的老版本也是不走CDN,因此這一層主要依賴Nginx的共享緩存,分配100M的共享空間,在大促時命中率也可以到接近20%。

  • JVM本地緩存

    JVM的堆內存主要是針對商品的基本信息和特殊屬性信息進行本地緩存,支持動態接口商品熱點數據,依賴Guava組件實現的LRU緩存淘汰算法,大致5000個熱點sku數據,數據量在5M左右,這是第三層的數據保護,大促時命中率在27%左右,另外強調一下,這里的java對象可動態配置成弱引用或者是軟引用,一般建議采用弱引用,這樣避免內存增長過快,導致頻繁的GC。

3、數據異構,減少強依賴

數據異構帶來的好處是可以減少一些基礎服務的強依賴,之前老板提的一個目標就是基礎服務掛了,上層業務還能很好的活著,但是京東這個數據體量來看成本是非常巨大的,因此APP單品頁選擇部分數據異構,減少基礎服務接口的強依賴,主要是商品的基礎數據、擴展屬性信息、商品的詳情數據,全量數據同步一次之后通過中間件JMQ進行增量的數據同步變更,存儲使用的是緩存中間件jimdb(redis緩存)。

4、并發請求異步化

APP單品頁前期屬于野蠻發展,很多RPC的依賴極其不合理,比如依賴關系沒有層次概念,超時時間設置超長、內外網接口同時依賴,造成任何的服務質量變差和網絡抖動對整體API影響非常大,因此進行了一次SOA化改造,主要工作是把單品頁系統從大網關分離出來,然后制定服務接入標準并進行改造,第三方面就是上游基礎服務調用并行化,系統整體并發能力及穩定性得到了極大的提升。

服務依賴的標準

  • 依賴接口必須是內網服務,不允許依賴外網服務;

  • 接口超時時間不超過100ms,并且除了一些核心數據,比如商品、價格、庫存,其他都不進行重試;

  • 核心接口必須可支持跨機房的雙活容災,client端出現問題必須可切換,并且要有降級方案;

  • RPC調用最好是依賴中間件JSF,這樣是點對點的長連接服務,減少每次建連的開銷,HTTP依賴需要經過內網的LB,增加一層代理的開銷,會出現一些不可控的問題。

隨著流量不斷增加,并行化遇到了瓶頸,每次請求會創建大量的線程,線程的維護和上下文切換成本本身比較消耗CPU資源,因此基于現有HttpClient和JSF基礎組件的異步化支持,進一步進行異步化的改造,單機壓測效果還是比較明顯,并發能力提升40%。

5、監控

系統流量到一定程度,系統的各維度監控尤為重要,可以幫助我們縮短排查、定位問題的時間,甚至可以幫助預警風險,當前APP業務從用戶到后端整個服務鏈條的監控都已經非常完善,包括各運營商入口流量的監控、內外部網絡質量、負載均衡、以及網關流量的監控以外,我重點介紹下單品頁業務層的監控,下邊是業務監控系統數據異步埋點的架構,主要分為兩類數據,第一業務指標數據比如單品頁各渠道訪問數據,通過UDP協議實時埋點到Kafka,然后storm實時在線分析形成最終需要的數據落地,另一類是大流量數據,比如系統異常信息落到磁盤日志中,然后通過logCollector異步發送到Kafka中,這類數據對磁盤IO、網卡IO的流量占比大,針對磁盤IO,會按照文件大小100M滾動生成日志文件,數據搬走之后進行刪除操作,網卡IO在數據傳輸過程中進行了限速,按照1m/s的速度進行傳輸,可進行動態調整,基本對業務不產生任何影響,大促峰值期間會針對一定比例降級。

業務系統除了基本的服務器各項指標CPU、MEM監控,服務的性能、可用率監控以外,介紹幾個比較實用的業務能力監控:

  • 方法tree監控,一次請求在單品頁SOA系統內部所經過的每一個類的方法作為結點形成這么一顆樹,這棵樹非常直觀看到系統內部的依賴結構關系和任何一個節點的請求量的大小,如果性能、可用率、異常量、訪問量出現異常可第一時間標紅報警,出現任何故障可第一時間聚焦到具體某一個點上,極大提升了定位和處理故障的時間;

  • 異常監控 系統依賴的外部服務以及系統內部拋出的任何一條異常的堆棧信息都被異步埋點記錄下來,進行實時的統計和報警,對系統健康度的把控起到至關重要的作用;

  • 用戶行為的跟蹤,詳細記錄用戶在什么時間做了什么事情以及當時的網絡情況,方便用戶出現問題時回放出問題時的現場,快速幫助用戶解決問題。

監控細節還有很多,以上幾個監控手段對當前業務系統幫助非常大也是非常實用的一些能力,現在業務系統已經做到非常透明,任何人都可以清晰看到系統的健康度,并且部分服務具備通過故障自動容錯的能力,對系統整體的穩定性提供了非常大的保障。

6、限流手段

京東APP上所有商品價格庫存都是分區域的,因此很多刷子以及爬蟲不斷的來爬京東各區域的價格、庫存和促銷信息等,有一個很明顯的特征就是大量刷子刷時用戶登錄態的占比會明顯下降,因此單品頁針對用戶的行為實時行為數據進行分析和控制:

  • 流量清洗能力,根據用戶的pin、IP的實時分析和清洗,并可以根據已登錄和未登錄做不同策略;

  • 系統過載保護能力,任何時候不能讓系統掛掉,把明顯的惡意流量清洗之后進行按一定策略進行排隊,保障流量不超過系統極限負載,同時給用戶比較友好的一些交互體驗。

7、壓測

單品頁壓測比較麻煩,一方面壓測的流量大,對線上可能會造成很多不可預知的問題,另一方面涉及的基礎服務比較多,牽涉的人就多,每次壓測要協調上下游幾十號人支持,協調成本比較高,第三方面壓測的商品數量都在上百萬的商品,每次壓測的SKU會變更,腳本變更比較大,第四每次壓測完成之后需要人工形成壓測報告并分析其中的薄弱環節問題,因此APP端產出了一個自己的壓測平臺,通過流程方面來協助解決以上幾個問題:

  • 啟動壓測任務可自動收集壓測數據并產出需要的壓測腳本;

  • 線上流量的隔離;

  • 通知相關方,確認壓測時間和壓測方案;

  • 按照壓測腳本逐步進行壓測任務執行;

  • 形成壓測報告,并分析壓測過程中問題點。

壓測數據準備方面:

  • 線上流量日志進行回放,并且按照壓測目標放大到一定倍數來回放;

  • 按照各品類的流量占比選出一部分商品作為熱點數據來進行壓測,檢驗各環節對熱點數據的處理是否合理;

  • 針對一些埋點以及統計要能清洗掉這部分數據,目前主要是根據請求的一些固定特征,比如設備號和特殊標識來進行區分,并且上下游都要能做到一致的數據清洗規則。

四、未來方向

單品頁還有很大的一些優化空間,比如為適應快速的業務迭代進行系統重構、jvm垃圾收回策略和堆內存分配大小的調整、異步化的改造等等優化正在進行,未來單品頁最重要的幾個方向:

  • 動態配置化:不同品類商品可根據單品頁元素動態形成一個個性化的單品頁,做到完全樓層可配置化;

  • 精細化:流控、自動化降級等方面能夠根據用戶特征,比如用戶級別、地域等可執行不同策略;

  • 智能化:根據用戶畫像數據展示更多個性化推薦的數據,千人千面,給用戶提供更有價值的信息。


Tags: 京東 手機

文章來源:http://mp.weixin.qq.com/s/tqWWAczUuUvtDuGVtMJYkg


ads
ads

相關文章
ads

相關文章

ad