500萬日訂單下的高可用拼購系統,到底暗藏了什麼「獨門祕籍」?

500萬日訂單下的高可用拼購系統,到底暗藏了什麼“獨門秘籍”?

【51CTO.com原創稿件】在大流量、高銷量的背後,是我們近半年來付出的努力,針對拼購系統瞬時高併發能力的優化與升級,才能保證消費者絲滑順暢的購物體驗。下面就來介紹下蘇寧拼購系統應對大促的術與道。

術為用:拼購系統高可用的架構設計

“術”是架構設計的方法論。拼購系統的架構歷經多次更新和迭代,其目的是打造一個高可用、高性能、易擴展、可伸縮性強的應用系統。

將整個過程精煉出來,我們主要做了三個方面的工作:

  • 系統架構優化設計
  • 數據庫性能的優化
  • 應用高可用的優化

系統架構優化設計

根據康威定律,組織形式等同系統設計。拼購系統之前為了滿足快速的開發迭代節奏,所有功能是放在一個集群中的。

隨著業務的發展,功能越來越複雜,單一集群已經成為限制系統性能的最大瓶頸。

500萬日訂單下的高可用拼購系統,到底暗藏了什麼“獨門秘籍”?

圖 1:蘇寧拼購系統架構設計

因此,系統優化所做的第一件事情就是對拼購系統架構進行了重構。一方面,進行橫向切分,將系統分層,包括:

  • 網絡層:通過 CDN 加速響應。一方面 CDN 緩存提高靜態內容訪問速度,減少服務端壓力;另一方面,CDN 內部網絡專線,加快回源速度。
  • 負載層:包括四層負載和七層負載。功能包括流量調度、流量控制、安全防護、黃牛防護等,另外在負載層也做了一些輕量級業務的 Lua 聚合,以提高響應性能。
  • 應用層:這層主要實現業務功能邏輯。
  • 服務層:為應用層提供原子服務,如會員、領券、尋源、時效、生成訂單、支付等。
  • 數據層:提供數據存儲訪問服務,如數據庫、緩存等;提供數據抽取分析服務,如 Hbase、Hive。

另一方面,針對拼購的業務特性,進行縱向切分,將原來耦合的功能邏輯拆分為三層:PGS-WEB、PGS-TASK-WEB、PGS-ADMIN_WEB。

每個模塊獨立集群部署,集群之間通過分佈式遠程調用與服務層提供的原子服務協同工作。其中:

  • PGS-WEB:前臺業務處理模塊。包括展示、交易、營銷三個單元模塊。每個模塊又能分割為更小粒度的子模塊。

比如營銷模塊就又能細分為四個輕量級玩法模塊:邀新團、砍價團、膨脹紅包和助力團,可以針對業務需要,對不同模塊進行拔插、拆分和擴展。

  • PGS-TASK-WEB:中臺定時任務處理模塊,主要用於處理定時任務,另外支付邏輯也在這一層。
  • PGS-ADMIN_WEB:後臺管理模塊,主要用於運營人員維護活動、商品、玩法等。

數據庫性能優化

在高併發場景下,提交訂單、生成拼團記錄、查詢訂單等操作,會對數據庫造成很大壓力,而這些一致性要求高的操作又不能直接使用分佈式緩存替代數據庫。

而給數據庫降溫,提高數據庫的併發處理能力,必須讓數據庫具備橫向擴展能力。因此我們基於 Mycat 數據庫中間件實現了拼購系統數據庫的分庫分表策略。

500萬日訂單下的高可用拼購系統,到底暗藏了什麼“獨門秘籍”?

500萬日訂單下的高可用拼購系統,到底暗藏了什麼“獨門秘籍”?

圖 2:高併發場景下 MySQL 數據庫負載能力趨勢

Mycat 是 MySQL 分庫分表中間件,和 Web 服務器的 Nginx 類似,是應用與數據庫之間的代理層。

由於 Mycat 是開源中間件,這裡對技術實現不做闡述,主要講下它在拼購系統下是如何應用的。

如下圖所示,業務邏輯的數據操作通過 Mycat 分為三個庫 DataNode 1~3,這個分庫過程應用本身是無感知的。

500萬日訂單下的高可用拼購系統,到底暗藏了什麼“獨門秘籍”?

圖 3:蘇寧拼購系統基於 Mycat 的分庫架構

每個庫一寫兩讀,針對團和團詳情的操作分片規則基於團 ID(GROUP_ID),針對訂單的操作分片規則基於訂單 ID(ORDER_ID)。

另外,還有一個單獨的 BackupDB 用於大數據抽取和數據備份,通過 Canal 保證 BackupDB 中是全量數據。

當 Mycat 出現問題時,我們可以通過應用層的數據源切換,降級為單庫,保證業務。

應用高可用優化

對於應用層面的優化,主要包括分佈式緩存和異步化兩方面。

利用 Redis 分佈式鎖解決併發場景一致性問題

比如為了防止訂單被重複處理,我們使用 Jedis 的事務 Transaction + SETNX 命令來實現 Redis 分佈式鎖:

  1. Transaction transaction = jedis.multi();//返回一個事務控制對象
  2. transaction.setnx(tmpLockKey, "lock");//Set if Not Exist
  3. transaction.expire(tmpLockKey, locktime);
  4. List rets = transaction.exec();//事務執行

利用 Redis 實現活動庫存,解決數據庫資源競爭問題

對於每一個拼團活動,我們是維護了活動庫存的,或者叫做資格/剩餘數,並非真正的實際庫存。

在 1 元秒殺等活動中,這個活動庫存的變化會很迅速,大量數據庫 UpDate 操作,造成行鎖非常影響系統吞吐率。

優化方案是 在Redis 中做活動庫存扣減,並以一定週期同步給數據庫:

  1. /**
  2. * Redis緩存扣減活動庫存
  3. * */
  4. private Long updateStoreByRedis(String actId, String field,
    int count) {
  5. String key = redis.key(PGS_STORE_INFO, actId);
  6. // 如果活動庫存緩存信息存在,則更新對應field的數量
  7. if (!redis.exists(key)) {
  8. // 從數據庫讀取該活動庫存信息並初始化到redis
  9. ActivityStoreEntity entity = queryStoreInfoFromDb(actId);
  10. if (entity == null) {
  11. return -1L;
  12. }
  13. Map values = new HashMap();
  14. values.put(PGS_STORE_ALL,…);
  15. values.put(PGS_STORE_REMAIN, …);
  16. values.put(PGS_STORE_LOCK, …)
  17. redis.hmset(key, values);
  18. // 若活動有效期內庫存緩存信息失效,初始化緩存信息一小時
  19. redis.expire(key, ONE_HOUR);
  20. }
  21. return redis.hincrby(key, field, count);
  22. }
  23. /**
  24. * Redis同步活動庫存給數據庫
  25. * */
  26. public int syncActivityStoreToDB(String actId) {
  27. try {
  28. // 判斷同步鎖狀態
  29. String key = redis.key(PGS_STORE_SYNC, actId);
  30. if(!redis.exists(key)){
  31. 更新活動可被鎖庫存數量
  32. redis.setex(key, actId,STORE_SYNC_TIME);
  33. }
  34. }
  35. } catch (Exception e) {
  36. Log;
  37. }
  38. }

異步化操作,消除併發訪問高峰

比如支付完成後,有一系列的後續處理流程,包括活動庫存扣減、拼團狀態變更等,其中有些邏輯實時性要求高,要同步處理。

有些則可以通過異步化的方式來處理,像通知物流發貨。我們採用 Kafka 隊列來進行異步通信,讓下游系統進行消費處理。

道為體:拼購系統高併發下的保障體系

“以道馭術,術必成。離道之術,術必衰。”我們所有的架構優化與升級最終目的是為了保障促銷高峰的穩定性。

拼購系統高併發場景下的保障之道,是以合理的容量規劃為基礎,全面覆蓋的監控體系為支撐,形成的完善的限流+降級+防控策略。

全鏈路壓測與容量規劃

根據業務預估量,生產環境針對蘇寧拼購全鏈路場景的壓測,才能做出合理的容量規劃。

目前,我們的壓測系統,可以支持引流壓測,即將線上真實流量複製下來,生成腳本,進行壓測。最大程度保證了壓測和真實情況的一致性,從而使容量規劃更精確。

端到端覆蓋的監控體系

目前蘇寧拼購的監控體系能夠做到端到端的覆蓋,包括客戶端->網絡->服務端的監控。

其中,客戶端監控依賴於覆蓋 PC + WAP + App 的終端日誌。網絡監控主要是 CDN 日誌和撥測數據。

服務端監控手段最為豐富,包括:

  • 服務器系統狀態監控:CPU、內存使用率、網卡流量、磁盤 IO 等。
  • Web 服務器監控:實時展現 Web 服務器的 Http 連接數、響應時間、Http 異常、狀態碼等指標。
  • 應用服務器異常監控:實時彙總應用異常堆棧信息。
  • JVM 狀態監控:實時展現JVM的內存、線程、GC 和 Class 的使用狀況。
  • NoSQL 監控:Redis 每分鐘命令數、大對象、連通性等的監控。
  • 數據庫監控:數據庫層面各項指標監控。
  • 調用鏈監控:實時展現應用間調用關係,反饋鏈路系統健康狀況。

這些監控系統通過 traceId 相串聯,與基礎運維平臺打通,最終通過決策分析平臺聚合,實現智能告警。

500萬日訂單下的高可用拼購系統,到底暗藏了什麼“獨門秘籍”?

圖 4:端到端監控體系與告警決策平臺

流量控制與風險控制

流量控制是針對 88 拼購日零點峰值瘋狂流量超出預期,所設置的限流,以保護好自身應用,否則出現雪崩式連鎖反應。

目前拼購的流控系統可以支持多個維度的流控策略。包括最基礎的 JVM 活躍線程數流控,針對用戶 IP、UA 和會員編號的限流,針對核心接口的限流策略,針對爆款商品的限流策略等等。

500萬日訂單下的高可用拼購系統,到底暗藏了什麼“獨門秘籍”?

圖 5:拼購流控系統架構

風險控制是針對 88 拼購日爆款商品被黃牛刷單風險的防控策略。除了傳統的黃牛庫名單,拼購的風控策略包括對用戶、地址、事件行為、設備指紋等的判斷。

區別於非黑即白的防控,拼購採用打分的方式對用戶進行畫像,對潛在的風險用戶採取短信驗證、滑動驗證、人臉識別等一些列挑戰模式。

大促準備與應急預案

大促準備工作是指結合業務的促銷節奏,梳理的一系列大促準備工作,包括非核心定時任務的提前降級、生產操作權限的回收等。

應急預案是針對大促可能發生的突發性事件梳理的預案,應急預案是建立在降級手段的基礎上的。

比如關鍵時候對部分功能的降級關閉操作,棄車保帥,保障購物流程的正常;再比如針對服務器性能瓶頸的降溫手段,只有在準備好應對一切突發情況的前提下,才能保證每次大促的順利完成。

結束語

路漫漫其修遠兮,今年的 88 蘇寧拼購日已經告一段落。未來向我們提出了更多的挑戰與機遇。

如何進一步突破系統性能瓶頸,如何給用戶提供個性化的推薦與服務,如何將拼購做成一個開放的社交化電商平臺,蘇寧拼購技術團隊要做的工作仍然有很多。

我們將繼續前行,勢不可擋,併為大家帶來持續的技術分享與更新。

簡介:朱羿全,南京航空航天大學碩士研究生畢業,蘇寧易購消費者研發中心高級技術經理,主要負責易購各系統架構優化與大促保障工作。先後參與了易購整站 Https 改造、蘇寧拼購架構改造、先知業務監控平臺建設等工作。專注於打造高可靠、高性能、高併發服務系統的技術研究。


分享到:


相關文章: