開發與維運

首次揭祕!看大麥如何掌控超大規模高性能選座搶票

作者| 阿里文娛技術專家 恆磊、阿里文娛高級開發工程師 新錢

一、背景介紹

隨著現場娛樂行業的不斷髮展,各類演出層出不窮,越來越多的演出開啟選座購票滿足用 戶的自主選座需求。大麥的選座不僅面向中小場館類的劇院演出,還面向大型體育賽事、大型 演唱會等超大型場館(如鳥巢近 10 萬座)。選座類型搶票的特點是“選”,由於“選”的可視化以及超大場館在數據量上對大麥是很大的挑戰。本文通過服務端和前端上的一些解決方案來探討 如何支撐超大規模場館的高性能選座,通過本文的一些技術方案希望可以對讀者在一些高併發實踐中提供幫助。

二、核心問題

首先看一下普通商品的秒殺,拿某款手機秒殺來說,一般情況下,一場手機只有幾個型號, 比如中低檔、高性能檔、旗艦等,處理好這幾個商品的庫存即可。對於選座類搶票而言,每一 個場次的所有的每一個座位都可以認為是一個不同的商品,場館大小不一,大的鳥巢有 10w 座 位。也即是說一個選座類搶票就涉及 10 萬級別的商品,如果多個項目同時開搶,整體數量會很 龐大。目前大麥電商側的商品維度是票檔,座位並不是商品粒度,所以無法利用集團的秒殺能 力,選座類搶票涉及電商、選座、票務雲產銷,是對大麥整體能力的考驗。
先來看看整個選座購票的流程:以林俊杰長沙測試項目購票為例。
用戶打開需要的場次項目詳情頁

image.png

②點擊選座購買,打開選座頁面,查看座位圖及票檔

image.png

③選擇一個看臺區域,選擇喜歡的座位,點擊確認選座

image.png

④進入下單頁面,填寫手機號收貨地址,創建訂單

image.png

⑤提交訂單完成付款、出票。 其中,2、3、4 環節都與選座相關。 從流程上看,選座的核心關鍵技術在於:
座位圖的快速加載。快速加載其實就是選座頁面的讀能力。選座頁面需要下載座位底圖、 座位基礎信息(排號等等)來做渲染,同時需要票檔、該場次每個座位的狀態,來決定是可售 還是鎖定還是已經售出。
對於大型場館座位 5 萬-10 萬,渲染一個選座頁面需要的數據量都很大。
②高併發。由於熱門演出票的稀缺性,同時搶票的人數可能達到幾十萬。如何支撐如此高 的併發和吞吐是一大考驗。
③座位狀態更新的及時性 當某個座位售出後,需要及時更新座位狀態。
④搶票體驗:搶票時熱門的看臺某個座位可能幾十個人併發去搶,如何儘量提升用戶的體驗,儘量讓更多用戶一次性購買成功,體驗更好。

三、高性能選座實踐

針對高性能選座的核心要求,我們從如下幾個維度去闡述我們在選座類搶票上的實踐。

1. 動靜結合

選座的瓶頸數據量“首當其衝”。從邏輯上講,一個座位完整的展現到用戶面前,需要包含 座位的看臺、排號、價格、售賣狀態等信息,其中 看臺、排號等等是不變的,並可提前預知的; 售賣狀態等時根據項目的進行會動態變化的。所以把選座的數據拆分為動態、靜態數據。對於 大型場館如 10 萬場館,用戶打開一個選座頁,座位的靜態數據(座位 id,票價 id,是否固定套 票,座標 x,y,和舞臺角度,哪個看臺,幾排幾號等等),這些數據大概 15M 左右。再加上動 態數據如票檔狀態、顏色、看臺狀態、座位狀態,10w 場館大概 2M 左右。也就是說如果不做 處理用戶僅僅打開選座頁就需要 17M 以上的數據量。如果選座數據存儲在 oss 上,如果每人下 載 15M,10w 人同時搶票則需要 1500G 帶寬,帶寬成本很高。為了解決靜態文件訪問速度問題, 將靜態數據從 oss 直接接入到 cdn。同時為了保障數據最新,靜態數據採用版本控制。

2. 靜態數據的預加載

上面提到帶寬峰值很高,為了降低峰值且提升體驗,客戶端引入了靜態數據預加載。靜態 信息結合預加載的處理,為處理大數據量的座位信息提供了時間上的餘量,用戶在打開選座頁 時優先顯示靜態信息,可有效降低用戶等待時間,提升用戶的體驗。
通過大數據分析結合用戶的行為習慣,確定預加載的場次類型,提高預加載的命中率。

image.png

預加載+預解析,完成了繪製基本場館信息的數據準備,再將數據提前與畫座 View 綁定, 預渲染 View 進而達到選座頁秒開效果。

3. 座位數據編碼

動態、靜態數據量大制約了我們實現高吞吐,同時也浪費了服務帶寬和用戶流量。所以需 要壓縮,壓縮到一定的可接受的範圍。只有數據量足夠小,才有辦法做到高吞吐。
1)靜態數據編碼 在處理大數據量的座位(例如十萬級)僅有靜態數據的預加載往往是不足的,預加載並沒有從根本上處理座位數據量大的問題,同時對於類似體育比賽這種多日期多場次的場景,由於預加載的使用存在緩存量的控制,往往影響預加載的命中率。 而數據重編碼和數據壓縮的使用,是從源頭解決問題的有效思路。
座位數據的重編,捨棄傳統的 xml 和 json 格式,不僅可以有效壓縮數據大小,還對數據安 全提供了保障,即使被拿到了接口數據,因為缺乏數據編碼的協議,也無法獲取有效的原始信 息。
2)座位靜態數據壓縮整體框架 目前大麥針對自己特有的座位數據特點,結合高效二進制編碼方案進行座位數據的重新編碼,再使用通用的無損壓縮進一步縮小數據體積,從而減少了座位數據的網絡傳輸時間,從根本上解決大數據傳輸導致的時延問題:

image.png

基於二進制的數據編碼,既保障了數據安全性,又保證了在數據解析中的高效性,即使數 據壓縮的使用也比 json、xml 的解析具有更少的時延。
同時兼具工具化的批量生產方式,又進一步解決了數據構建問題。

image.png
通過端上和 server 端的握手協商過程,實現了數據編碼和通用壓縮方式靈活組合,sever 端 可以針對不同的端下發相應的壓縮格式文件:

image.png

結合 CRC 的思想,制定了兼容 IOS、Android 和 H5 三端的基於座位屬性的縱向 hash 校驗。 相比 md5 等普通的散列計算方式,在處理 6 萬級座位多維度信息時,在端上實現了十幾毫秒、 H5 側 50 毫秒左右的全量數據檢測,使得在不佔用多長時間的情況,可以驗證數萬級座位解析 的準確性。
經過這編碼到檢測的完整鏈路,實現了減少數據的體積的同時,又能達到比傳統 xml 和 json
數據的高效解析、高安全性。

image.png

其中 quantum 是大麥端上自研的基於動態比特和字典的壓縮算法,結合大麥特有業務場景, 實現了高壓縮比和快速數據解析:

image.png
3)座位動態數據的編碼處理 a)動態數據的難點選座動態接口主要涉及票檔情況、看臺情況、座位狀態。數據量最大的是座位狀態。以一 個 5 萬座位的場館為例,每個座位都要返回一個狀態供前端渲染。採用座位 id 和狀態鍵值對的 方式,由於座位較多使得整個返回結果過大,5 萬座位的場館返回 1M 以上的數據。如果打開 一個選座頁需要吞吐 1M 數據量的化,接口基本不可用了。之前的策略是按照分組策略,5 萬 大概會分 10 個組,這樣每個請求大概 100k 數據量,這樣才能達到接口基本可用,不過端上需 要請求 10 次才能拿到整個場次的狀態,可想而知性能會有多大影響。假如 5 萬座位的場館,10 萬峰值搶票,那麼僅僅這個接口就需要 100 萬的 qps,所以肯定會逢搶必掛。
b)方案
目前接口是通過 mtop 協議,我們思考的前提:目前mtop 不支持 byte[]數組流,只支持 json等格式的字符串結構。如何把返回的數據減小,採用一個儘量簡潔的方案,同時調用一次返回 整個場館座位狀態,是我們努力的方向。
數據量大主要是因為有很多冗餘的座位 id。有沒有辦法不依賴這些座位 id?既然我們做的 動靜分離,靜態數據裡已經涵蓋了座位 id,我們動態接口裡只需要對應的返回狀態即可,即按 照靜態裡面的順序返回座位狀態。同時我們把返回結果進行簡單的相鄰狀態合併將進一步降低 返回結果大小。假設用戶選座座位符合正態分佈概率,平均長度 5w 座位平均返回不到 20k。
當然如果我們 mtop 協議支持二進制流,那麼我們可以用 bit 位進行存儲,可以進一步降低 返回結果的大小。

4. 高效緩存

1)緩存
面向這麼高的 TPS,tair 是不二首選。採用 tair + 本地緩存,來支撐如此高的數據峰值。 提到 tair,提一下我們這邊的一些策略。 用戶進到選座頁是一個個的看臺,我們設計了一級 stand cache,即看臺級別的 cache;用戶會進行選座位,我們又加了一級 seat cache,即為座位粒度的 cache。兩級 cache 保障用戶查看臺和用戶下單選座都能命中緩存。standcache 是熱點 key,從選座的場景是允許數據非準實時 的,所以引入了 tair localcache 和 guava localcache 來增加吞吐,以此降低對 tair 的讀壓力。
2)保護下游系統
目前採用的策略是 對下游的調用採用加鎖,tair 全局鎖。拿到鎖的才去請求票務雲底層數 據。拿到鎖的進程去更新 tair 緩存。其實從這裡看對 tair 的寫還是 qps 比較小的,但是每次爭搶 鎖對 tair 的讀還是不算太小。通過採用本地的鎖 + 隨機透傳來減少 tair 鎖耗費的讀qps。為了 對下游依賴做降級,增加了數據快照,每次對下游的調用記錄數據快照。當某次調用失敗採用 之前的快照進行補償。
3)保障數據更新及時
由於我們採用了 tair 全局鎖,可以按照秒級控制下游調用。調用採用異步觸發。最短 1s 內 會觸發我們發起對下游的調用。如果我們想最大化利用票務雲庫存能力,給用戶的延遲在 1s 以 內,我們有一些策略。拿到鎖的線程 1s 內調用數據更新任務,在數據更新任務裡做一些策略, 1s 內是發起 1 次還是多次對票務雲的調用,調用越多 tair 更新越及時。由於用戶有一定的選座動作,一般情況下 500ms 的延遲用戶基本無任何感知的。
4)緩存預熱 預熱一下緩存,對用戶體驗和系統性能很有幫助。搶票類項目採用一定的策略做自動化預熱。

5. 安全及容災

1)安全 從上文看大麥座位數據做了編碼和加密,同時存儲路徑做了混淆,保障不到開搶時間座位數據無法被破解,保障了選座數據的安全性。此外選座頁佈局防控策略,保障是真正需要點擊座位才能完成下單,防止機刷、防止繞過選座直接下單。通過類似策略降低了選座的無效流量, 提高了穩定性。
2)容災
選座主要在以下幾個方面做了容災。靜態數據存儲在oss 上,目前採用跨地區存儲容災;tair 緩存採用主備緩存,出故障時可以做切換;服務端在 pc 和無線做了集群隔離。

四、總結

本文通過在數據處理、選座性能、緩存等等策略上來闡述了筆者在大麥高性能選座上的一 些實踐。通過這些實踐目前大麥可以輕鬆的承載數十萬人的頂級流量的搶票項目。

Leave a Reply

Your email address will not be published. Required fields are marked *