如何設計一個高可用、高併發秒殺系統

騰訊技術工程發表於2020-03-10

如今的網際網路已經在海量服務領域有了很成熟的理論,因此自己也很慶幸,能夠從 0 到 1 完整踐行海量服務。微視春節專案中的集卡瓜分活動,是一個典型的秒殺場景,自己參與其中,分享一些心得和總結。

如今的網際網路已經在海量服務領域有了很成熟的理論,因此自己也很慶幸,能夠從 0 到 1 完整踐行海量服務。微視春節專案中的集卡瓜分活動,是一個典型的秒殺場景,自己參與其中,分享一些心得和總結。

秒殺系統的難點

  • 友好的使用者體驗

  • 使用者不能接受破窗的體驗,例如:系統超時、系統錯誤的提示,或者直接 404 頁面

  • 瞬時高併發流量的挑戰

  • 木桶短板理論,整個系統的瓶頸往往都在 DB,如何設計出高併發、高可用系統?

如何設計

如何設計一個高可用、高併發秒殺系統

上圖是一個典型的網際網路業務,使用者完成一個寫操作,一般會通過接入層和邏輯層,這裡的服務都是無狀態,可以通過平行擴充去解決高併發的問題;到了 db 層,必須要落到介質中,可以是磁碟/ssd/記憶體,如果出現 key 的衝突,會有一些併發控制技術,例如 cas/加鎖/序列排隊等。

直筒型

直筒型業務,指的是使用者請求 1:1 的洞穿到 db 層,如下圖所示。在比較簡單的業務中,才會採用這個模型。隨著業務規模複雜度上來,一定會有 db 和邏輯層分離、邏輯層和接入層分離。

如何設計一個高可用、高併發秒殺系統

漏斗型

漏斗型業務,指的是,使用者的請求,從客戶端到 db 層,層層遞減,遞減的程度視業務而定。例如當 10w 人去搶 1 個物品時,db 層的請求在個位數量級,這就是比較理想的模型。如下圖所示

如何設計一個高可用、高併發秒殺系統

這個模型,是高併發的基礎,翻譯一下就是下面這些:

  • 及早發現,及早拒絕

  • Fast Fail

  • 前端保護後端

如何實現漏斗型系統

漏斗型系統需要從產品策略/客戶端/接入層/邏輯層/DB 層全方位立體的設計。

如何設計一個高可用、高併發秒殺系統

產品策略

  • 輕重邏輯分離,以秒殺為例,將搶到和到賬分開;

  • 搶到,是比較輕的操作,庫存扣成功後,就可以成功了

  • 到賬,是比較重的操作,需要涉及到到事務操作

  • 使用者分流,以整點秒殺活動為例,在 1 分鐘內,陸續對使用者放開入口,將所有使用者請求打散在 60s 內,請求就可以降一個數量級

  • 頁面簡化,在秒殺開始的時候,需要簡化頁面展示,該時刻只保留和秒殺相關的功能。例如,秒殺開始的時候,頁面可以不展示推薦的商品。

客戶端

  • 重試策略非常關鍵,如果使用者秒殺失敗了,頻繁重試,會加劇後端的雪崩。如何重試呢?根據後端返回碼的約定,有兩種方法:

  • 不允許重試錯誤,此時 ui 和文案都需要有一個提示。同時不允許重試

  • 可重試錯誤,需要策略重試,例如二進位制退避法。同時文案和 ui 需要提示。

  • ui 和文案,秒殺開始前後,使用者的所有異常都需要有精心設計的 ui 和文案提示。例如:【當前活動太火爆,請稍後再重試】【你的貨物堵在路上,請稍後檢視】等

  • 前端隨機丟棄請求可以作為降級方案,當使用者流量遠遠大於系統容量時,人工下發隨機丟棄標記,使用者本地客戶端開始隨機丟棄請求。

接入層

  • 所有請求需要鑑權,校驗合法身份

  • 如果是長連結的服務,鑑權粒度可以在 session 級別;如果是短連結業務,需要應對這種高併發流量,例如 cache 等

  • 根據後端系統容量,需要一個全域性的限流功能,通常有兩種做法:

  • 設定好 N 後,動態獲取機器部署情況 M,然後下發單機限流值 N/M。要求請求均勻訪問,部署機器統一。

  • 維護全域性 key,以時間戳建 key。有熱 key 問題,可以通過增加更細粒度的 key 或者定時更新 key 的方法。

  • 對於單使用者/單 ip 需要頻控,主要是防黑產和惡意使用者。如果秒殺是有條件的,例如需要完成 xxx 任務,解鎖資格,對於獲得資格的步驟,可以進行安全掃描,識別出黑產和惡意使用者。

邏輯

  • 邏輯層首先應該進入校驗邏輯,例如引數的合法性,是否有資格,如果失敗的使用者,快速返回,避免請求洞穿到 db。

  • 非同步補單,對於已經扣除秒殺資格的使用者,如果發貨失敗後,通常的兩種做法是:

  • 事務回滾,回滾本次行為,提示使用者重試。這個代價特別大,而且使用者重試和前面的重試策略結合的話,使用者體驗也不大流暢。

  • 非同步重做,記錄本次使用者的 log,提示使用者【稍後檢視,正在發貨中】,後臺在峰值過後,啟動非同步補單。需要服務支援冪等

  • 對於發貨的庫存,需要處理熱 key。通常的做法是,維護多個 key,每個使用者固定去某個查詢庫存。對於大量人搶紅包的場景,可以提前分配。

儲存層

對於業務模型而言,對於 db 的要求需要保證幾個原則:

  • 可靠性

  • 主備:主備能互相切換,一般要求在同城跨機房

  • 異地容災:當一地異常,資料能恢復,異地能選主

  • 資料需要持久化到磁碟,或者更冷的裝置

  • 一致性

  • 對於秒殺而言,需要嚴格的一致性,一般要求主備嚴格的一致。

實踐——微視集卡瓜分系統

微視集卡瓜分專案屬於微視春節專案之一。使用者的體驗流程如下:

如何設計一個高可用、高併發秒殺系統

架構圖

如何設計一個高可用、高併發秒殺系統
  • 客戶端主要是微視主 app 和 h5 頁面,主 app 是入口,h5 頁面是集卡活動頁面和瓜分頁面。

  • 邏輯部分為分:髮卡來源、集卡模組、獎品模組,髮卡來源主要是任務模組;集卡模組主要由活動模組和集卡模組組成。瓜分部分主要在活動控制層。

  • 獎品模組主要是發錢和其他獎品。

瓜分降級預案

為了做好瓜分時刻的高併發,對整個系統需要保證兩個重要的事情:

  • 全鏈路梳理,包括呼叫鏈的合理性和時延設定

  • 降級服務預案分析,提升系統的魯棒性

如下圖所示,是針對瓜分全鏈路呼叫分析如下圖,需要特別說明的幾點:

如何設計一個高可用、高併發秒殺系統
  • 時延很重要,需要全鏈路分析。不但可以提高吞吐量,而且可以快速暴露系統的瓶頸。

  • 峰值時刻,補單邏輯需要關閉,避免加劇雪崩。

我們的降級預案大概如下:

  • 一級預案,瓜分時刻前後 5 分鐘自動進入:

  • 入口處 1 分鐘內陸續放開入口倒數計時,未登入使用者不彈入口

  • 主會場排隊,進入主會場以 100wqps 為例,超過了進入排隊,由接入層頻控控制

  • 拉取資格介面排隊,拉取資格介面 100wqps,超過了進入排隊,由接入層頻控控制

  • 搶紅包排隊,搶紅包 100wqps,超過了進入排隊,由接入層頻控控制

  • 紅包到賬排隊,如果資格扣除成功,現金髮放失敗,進入排隊,24 小時內到賬。非同步補單

  • 入口處呼叫後端非關鍵 rpc:ParticipateStatus,手動關閉

  • 非同步補單邏輯關閉。

  • 二級預案,後端隨機丟請求,接入層頻控失效或者下游服務過載,手動開啟進入

  • 三級預案,前端隨機丟請求,後端服務過載或者當機進入。手動開啟

綜上,整個瓜分時刻體驗如下所示:

如何設計一個高可用、高併發秒殺系統

回顧下漏斗模型,總結下整個實踐:

如何設計一個高可用、高併發秒殺系統

相關文章