小米技術分享:解密小米搶購系統千萬高併發架構的演進和實踐

小米技術分享:解密小米搶購系統千萬高併發架構的演進和實踐

本文原文內容引用自高可用架構公衆號,內容有整理和修訂。

1、引言

大家對下面這個排隊的場景應該非常熟悉,這個是小米手機搶購的用戶排隊交互圖,大家看到這些排隊的兔子時,說明也有很多用戶在同一時間向小米搶購系統提交了購買請求。

 

▲ 小米手機搶購排隊中...

小米搶購系統後端服務面臨巨大的壓力,下圖可以反映小米搶購系統面臨的瞬間峯值壓力。這張圖截取自某年米粉節大秒服務後端其中一組LB(負載均衡層)的每分鐘請求總數的情況(橫軸的時間是UTC時間),如大家可以想象到的一樣,峯值流量是普通情況下流量的近10倍。

 

▲ 某年米粉節大秒服務後端其中一組負載均衡層的QPS統計情況

以上就是小米搶購活動時後端服務集羣面臨的壓力。小米搶購系統從2011年底誕生到成長爲一個扛過2次米粉節和多次爆品首發的高性能、高可靠的峯值系統,經歷了很多次大大小小的架構演進,本次分享將爲大家解密該系統的技術演進、設計思路、實踐總結等,希望能帶給您啓發。

(本文同步發佈於:http://www.52im.net/thread-2323-1-1.html

2、分享者

 

馬利超:小米科技的系統研發與大數據工程師,2013年畢業於大連理工大學,畢業後有幸加入小米搶購系統團隊,並參與了小米搶購系統開發、重構與調優。其人熱愛技術,對分佈式系統架構、高併發峯值系統、大數據領域、反作弊領域、搜索/廣告/推薦系統有濃厚的興趣。

3、相關文章

新手入門:零基礎理解大型分佈式架構的演進歷史、技術原理、最佳實踐

達達O2O後臺架構演進實踐:從0到4000高併發請求背後的努力

騰訊資深架構師乾貨總結:一文讀懂大型分佈式系統設計的方方面面

快速理解高性能HTTP服務端的負載均衡技術原理

子彈短信光鮮的背後:網易雲信首席架構師分享億級IM平臺的技術實踐

知乎技術分享:從單機到2000萬QPS併發的Redis高性能緩存實踐之路

4、小米搶購系統的前世今生

4.1 早期的架構設計

2011底,在小米手機首批30萬全部發完貨之後,接下來便是大家熟知的,每週二中午十二點,小米手機開放購買。在開放購買期間,海量的用戶請求瞬間衝擊過來,對於當時小米這樣一個初創公司,特別是一個剛成立不到半年的電商團隊來說,面臨的挑戰是巨大的。

面臨的問題大致如下:

1)第一次開放購買,在小米商城主站進行,在瞬時壓力下,整個主交易系統並沒有逃脫掛掉的命運;

2)開放購買活動是結束了,但是一週之後,下一輪的開放購買已經開始開放預約,開放購買又會如期而至。

爲了保證下次開放購買順利進行,留給小米網工程師團隊的時間是有限的,只有短短的7天時間。

經過技術團隊討論,爲了避免搶購時的峯值流量壓垮整個小米網,決定設計一套獨立的搶購系統。預約用戶通過在這套獨立的搶購系統中搶到購買資格,購買資格會異步的由資格數據同步模塊同步到用戶的購物車中,從用戶搶到手機那一時刻起,在規定的時間內,用戶小米商城完成下單和支付。

從此這版獨立的搶購系統承接了小米的所有的搶購,經歷過大大小小的優化與重構,最後又演化爲整個小米網的限流峯值系統。這版最初的搶購系統內部代號:TD。

這套系統早期的架設設計出發點是:

1)併發能力要儘量的高,能承受瞬時的峯值;

2)不能超賣(可容忍小量的超賣);

3)只有預約用戶可以購買,一個用戶只能買一臺;

4)要非常可靠,購買記錄不可丟失。

TD的早期技術架構圖:

 

如上圖所示,小米第一版搶購系統使用的技術棧:LVS + nginx + PHP + node.js + redis:

1)預約用戶信息緩存在遠端緩存集羣中,一主多從結構,具體在放號的過程中,對預約數據只有查詢操作;

2)放號業務邏輯層使用PHP開發(當時小米網PHP開發者居多),使用遠端緩存作爲數據中心,存放用戶的購買記錄,同時,每放一個資格號,記錄一條持久化的log(資格日誌),保障用戶購買記錄可靠;

3)使用node.js開發的資格日誌收集及統計模塊logagent,收集資格日誌,並將資格日誌發送到遠端的logserver;同時,logagent統計自己所在的機器上購買記錄的條數,由於事先均等的分配好每臺機器的商品銷售數量,當機器上購買成功的日誌條數大於等於分配的數量時,則在本地生成一個.Lock的文件;

4)PHP開發的放號業務邏Middle集羣中服務可能會輯中首先會檢查.Lock的文件是否存在,來標誌這臺機器上的資格數是否被放完;同時,logserver將用戶購買成功的資格同步到購物車及其他相關服務系統中。

這套架構的回顧和總結:

1) 伸縮性強:PHP開發的放號邏輯不持有狀態數據,狀態數據存在遠端數據中心或者由logagent控制生成本地文件鎖(.Lock)標識,伸縮性強;

2) 可靠性高:搶購成功記錄以日誌的形式記錄,保障數據可靠性。

該系統經過不間斷的優化,滿足了2012年及2013年上半年的搶購需求,應對的預約量在100萬級別。

毫無疑問,這個初期架構也存在很多問題:

1)單機處理能力有限:由於單機處理能力有限,如果要應對千萬級別的預約量時,假設不暴漏伸縮性問題的話,需要的資源數量是否能承擔的起?

2)logserver處理能力: logserver的管理能力有限,隨着搶購人數的增多,併發量的增加,當前邏輯下,每秒放的資格數量會增加,logserver是否能夠及時的處理這些資格記錄?

基於上述問題,接下來我們來看小米新一代搶購系統,也可以理解爲加強版。

4.2 加入了限流服務後的新一代搶購系統

2013年7月份,小米發佈了紅米手機,並與QQ空間合作首發,1分鐘內預約達到30萬,半個小時預約量達到100萬,72小時預約量突破500萬,小米手機的預約量從此進入了千萬級別,面對如此驚人的預約量,像之前分析的那樣,如何在短時間內應對這個突發的量級變化呢?(紅米手機發布前,技術團隊並不清楚將要面臨的挑戰)。

經過技術團隊討論之後,決定在搶購系統之前加一層限流服務,將流量限制在TD能夠處理的能力範圍之內,由此便演進出一個新的服務——限流服務,內部代號: TC。

新一代搶購系統的整體架構介紹如下:

 

最初的TC使用nginx+Lua開發,主要負責用戶預約驗證和每秒向後端放行流量控制:

1)TC在活動開始前,load預約用戶數據到nginx共享內存中;

2)使用Lua開發每秒放量計數邏輯,nginx的異步IO機制加上Lua的多協程處理能力,使限流層能夠達到一個很高的併發量;

3)Nginx是多進程運行,我們需要將預先限流層的每秒放行總量均攤到整個Nginx集羣的進程數量上,而非按照機器數量均攤。

TC與TD之間以token的形式交互,用戶從TC上取得放行資格,然後拿着這個資格去TD放量集羣中請求放量,TD放行通過,才代表最終的搶購成功。

有了上述的系統結構,只要放行控制得當,再高的流量壓力也不用怕了,我們也成功撐過了紅米首發。

從此這個小米開放購買預約量進入了千萬級別,紅米2首發預約量更是在兩千萬級別。

儘管系統併發能力有了大大的提升,但是整個系統仍有一些不足:

1)管理功能簡陋:活動過程中需要人工干預活動的結束,在TD服務將商品賣完後,手動執行命令設置TC內存中指定商品的銷售狀態爲售罄,這個誤操作風險非常高,並且延遲很高,在商品售罄後不能及時的通知用戶售罄狀態;

2)靈活性較弱:技術團隊對於lua使用還不夠靈活,TC也只能處理一些簡單的業務邏輯;

3)反應能力不足:前後端處理能力差距較大,一旦限流失誤,後端很快就會崩潰,管理體系的不完善,不能瞬時響應。往往在流量高峯下,再多1秒的請求量,就有可能使整個系統發生雪崩。反應能力的不足造成,系統的可靠性下降。

在TC限流服務優化的過程中,我們調研了其他高併發的語言,如: C/C++、 scala、erlang、node.js、golang等。

從學習成本、開發效率、運維便捷性等多方面評估,我們選擇使用golang開發了一版TC服務。在2013年11月,我們上線了golang版的TC服務,同時也針對這款golang版的TC限流服務和TD放號服務開發了統一的監控管理平臺,由監控管理平臺統一協調整個活動以及參與活動的商品的配置與狀態,在整個系統流程上保證了很好的連貫性以及運營的靈活性。監控管理平臺同時還負責監控各個服務的運行狀態,及時報警。

接下來的文章內容,我們將詳細介紹基於golang的小米搶購系統(內部稱爲“大秒”),也是本文的分享重點,請繼續往下閱讀。

5、整合了搶購限流峯值服務後的小米搶購系統:“大秒”

接上節,我們繼續詳細介紹這套最新架構。

時間回到2014年初,當時公司決定舉辦一場“米粉節”活動,全天6輪活動,多個國家、多款爆品同時參與搶購。業務場景將變得更加複雜,當天的併發壓力也會有一個量級的提升,原有的搶購系統已經不能適應如此複雜的業務場景了。

爲此,小米網技術團隊基於對 golang 應對高併發、大規模分佈式系統能力的肯定,完全基於 golang,重新設計了搶購系統,也就是我們目前使用的搶購限流峯值系統——“大秒”。

在整個系統設計的之初,我們充分考慮了:

1)靈活性及可運營性;

2)可運維性及可伸縮性;

3)限流與搶購放號的精準性。

從大秒第一天誕生到演化至今有很多次重構與優化,但一直沿用了設計之初的結構,接下來我們詳細瞭解下這套架構的技術設計以及填過的一些坑。

6、“大秒”系統的架構設計

 

大秒系統主要由如下幾個模塊構成:

1)限流集羣 HTTP 服務;

2)放號策略集羣 Middle 服務;

3)監控數據中心 Dcacenter;

4)監控管理體系 Master;

5)準實時防刷模塊 antiblack;

6)基礎存儲與日誌隊列服務:Redis 集羣、Kafka 集羣等。

整個大秒體系中大秒前端模塊 (HTTP/middle/antiblack) 和監控數據中心使用 golang 開發,大秒監控管理體系使用 Python + golang 開發。

7、“大秒”的前端架構設計

“大秒”前端的架構設計從三個系統展開:

1)限流集羣 HTTP 服務;

2)策略集羣 Middle 服務;

3)準實時反作弊 antiblack 服務。

 

7.1 限流集羣 HTTP 服務

搶購高峯時,通常會有幾百萬的用戶同時請求,瞬時流量非常大,HTTP 集羣頂在最前線,接受用戶的請求,將合法的請求發送的處理隊列,處理隊列設置一定的長度限制,通常情況下,搶購用戶數與銷售商品的比例在100:1,甚至更高,爲了避免系統不被沖垮,保障絕大多數用戶的體驗,我們認爲流量是部分可丟失的,當處理隊列滿時,丟棄入隊請求;

雖然設計上過載流量是部分可丟棄的,但是策略層處理能力是非常 power 的,即便是需要丟棄流量,也是按流量的惡意程度,逐級丟棄的,正常用戶購買請求不受影響。

我們使用基於規則的識別、離線畫像信息、機器學習邏輯迴歸等方法,識別惡意用戶,在系統高負載的情況下,這部分請求可以優先阻擊其發送到策略層,優先處理正常用戶的請求,保障用戶體驗過。

HTTP集羣中不同節點之間的所持用的狀態數據是一致的,處理邏輯也是一致的,所以整個集羣中的任何一個節點掛掉,在前端負載均衡能力下,服務的準確性與一致性不受任何影響。

7.2 策略集羣 Middle 服務

HTTP 模塊將滿足條件用戶的請求按照 uid 哈希的規則,轉發到 Middle 集羣中相應的節點,Middle 集羣根據商品放號策略判斷 (uid:sku:time) 組合是否可以分配購買資格,並返回給相應的 HTTP 服務;

使用 Middle 服務本地內存維護用戶的購買記錄信息,支持各種購買規則,比如:單次活動不限購買數量,單次活動僅限購買一款商品,單次活動每款商品僅限購買一次。

我們將 Middle 的放號邏輯抽象成一個有限狀態機,由商品的放號策略配置閾值來觸發放號狀態轉換,整個配置由 Master 節點統一管理與調度。

爲了提升整個系統的處理能力,我們將用戶狀態數據局部化,單用戶(uid)的所有相關信息全部路由到一臺 Middle 節點上處理。

但是有一點風險是,Middle 集羣中服務可能會出現活動過程中掛掉的風險,在搶購場景下,商品基本上是瞬時賣完,爲了保障系統的處理能力,我們主要從代碼層面做優化,review 代碼邏輯,保證服務應對異常的處理能力。

雖然理論上存在風險,但是在實際工程中,經歷過幾百次活動,還沒出現 Middle 節點掛掉的情況。

7.3 準實時防刷 antiblack 服務

 

基於日誌流的防刷架構,在每臺 HTTP 節點上部署日誌收集 Agent,使用高吞吐量的 Kafka 做日誌轉儲隊列,antiblack 模塊實時分析用戶請求日誌,基於 IP 粒度、Uid 粒度等做防刷。

雖然此處將 antiblack 模塊定義爲準實時防刷模塊,但是作弊信息識別的延遲時長在 1 分鐘之內,其中主要的時延發生在日誌的轉儲過程中。

8、“大秒”的監控管理體系

8.1 監控數據中心 dcacenter

 

1)監控數據中心數據種類:

1)業務級數據:過大秒的商品配置數據與實時狀態數據,當前活動的配置與狀態數據等;

2)系統級數據:大秒前端服務集羣通信地址配置,限流隊列初始長度配置,系統服務資源佔用情況,包括:CPU、MEM、連接數等;

2)數據採集方式:

同時使用push和pull模式採集業務級監控數據和系統級監控數據,業務級數據越實時越好,做到1秒採集處理,3秒可視化;對於 HTTP 節點和 Middle 節點採用pull的模式拉去系統監控數據和業務監控數據。

具體的優點如下。

a. 靈活性高:

由數據中心控制監控數據採集的粒度,在數據中心處理能力既定的情況下,可以根據前端集羣的伸縮規模,靈活的調整數據採集的粒度,比如米粉節時,大秒前端集羣擴容至過百臺,管理的過大秒商品的數量在400個左右,業務級監控數據量很大,此時監控數據採集時間間隔很容易降配至 2s。

對於除Http服務和Middle服務之外的服務集羣,如:redis,管理平臺各個模塊等可以使用監控數據採集agent,將採集到的數據週期性的push到redis隊列,dcacenter採集協程實時的從redis隊列中拉去消息,對於基礎服務以及python實現的服務,增加了監控數據採集靈活性。

b. 增強服務的可靠性與伸縮性:

大秒在設計之初採用push的方式,在每臺前端機器上部署一個數據採集agent,agent和大秒前端服務同時alive,才代表搶購系統健康運行。這樣即增加了系統的不穩定因素,由不利於系統的伸縮,將監控數據採集邏輯內置到前端golang程序中,提供tcp管理端口,在數據中心使用pull方式採集數據,很好的解決了這個問題。減少了服務的數量,增強了整個系統的可靠性與伸縮性。

3)數據ETL與數據緩存:

dcacenter同時負責將採集到的業務級數據及系統級監控數據,實時清洗,提取,轉換,結構化,並將結構化的數據存儲在自身內存中,定製通信協議(golang實現類redis通信協議),作爲一個數據中心,對整個管理體系Master及其他系統提供實時數據支持。

將dcacenter直接作爲數據中心,主要是出於數據的實時性考慮,省去中間轉儲環節,上層可視化系統、自動化活動控制系統、規則引擎系統等可以第一時間獲得前端實時的銷售狀態數據及服務的狀態數據。

8.2 監控管理中心 Master

監控管理中心的主要模塊如下。

a.倉儲庫存同步服務StockKeeper:

同步商品的倉儲系統中的實時庫存到秒殺系統,大秒系統擁有雙庫存保障,一個是實時倉儲庫存,一個是虛擬庫存也就是資格號,在搶購場景下只有當兩個庫存都有貨時,才能正常銷售。

b.商品策略控制器PolicyKeeper:

基於相應的策略觸發器(時間區間與庫存區間),當策略觸發時,比如12點整,搶購開始,爲相應的商品配置策略,並向大秒前端廣播商品配置變更命令,在通信基礎模塊的保障下,整個過程秒級內完成。

c.活動自動化控制ActKeeper:

基於監控數據中心獲取大秒前端的實時銷售數據,自動化的控制活動中的各個狀態,活動開始前逐層打開開關,活動開始時打開最後開關,活動過程中維護活動的售罄狀態,活動結束後初始化,整個搶購活動的過程無需人工介入;

d.數據可視化:

從監控數據中心提取實時的結構化系統級監控數據和業務級監控數據,將活動過程中的詳細數據實時可視化到管理頁面上,讓運營與銷售以及大秒管理員能夠及時瞭解當前活動狀態,並人工干預活動;

e.監控規則引擎:

監控規則引擎建立在監控數據中心之上,根據結構化監控數據判斷當前整個搶購系統的狀態,及時報警,以及半自動化控制。

f.其他:

大秒管理端管理大秒前端所有的數據、配置以及狀態,Master體系提供了詳細的管理工具與自動化服務。如果清理大秒前端Middle服務中的用戶購買信息等。

8.3 大秒配置管理數據流

 

整個搶購系統由 Master 體系中各個服務做統一的控制的,Master 控制商品狀態及配置數據的變更,控制當前活動的狀態,控制商品放號的策略等。

爲了保證時效性,商品、活動、系統等配置狀態的變更都需要將變更命令廣播前端集羣,這期間發生了大量的分佈式系統間通信,爲了保障命令及時下行,我們提取出了命令轉發服務:MdwRouter,用於廣播控制命令到大秒前端集羣。該服務模塊維護了到大秒前端長連接,接收 Master 下發的控制命令,並瞬時廣播,保障了整個控制流的處理能力。

舉個例子:

某年米粉節,我們單機房大秒集羣的規模在過百臺級別,假設爲 100 臺,管理的獨立的商品id的數量在 400 個左右,在這種量級的活動下,商品的放行策略是批量管理的,比如我們根據後端交易系統的壓力反饋,調整所有商品的放行速度,這時候需要廣播的命令條數在: 100*400=40000 級別,Mdwrouter 很好的保障了系統命令下行的速度,秒級完成命令下行。

9、小米搶購技術架構整體概覽

9.1 整個搶購服務閉環設計

 

▲ 整個小米網搶購系統服務閉環

整個小米網搶購系統服務閉環如上圖所示:

1)bigtap體系中大秒前端服務負責搶購時限流放號,並控制放號策略以及維護用戶在本地緩存中的購買記錄;

2)cart服務驗證token的有效性,並向counter服務發起銷量驗證請求;

3)counter服務是整個搶購系統最終的計數器, 海量的請求在bigtap服務的作用下已經被限制在可以承受的壓力範圍內,並且複雜的放號策略已經在大秒Middle服務中實現,counter只負責最終的計數即可。counter服務採用redis記錄相應商品的放號情況,根據預設的銷量,判斷當前請求加購物車商品是否有庫存餘量,並維護商品銷量;

4)bigtap體系中的dcacenter服務實時採集商品銷量,Master中活動自動化控制服務依據商品銷量判斷當前商品是否售罄,售罄則通過設置商品的售罄狀態,並通知大秒前端。

9.2 整個系統在2015年米粉節的實際應用情況

從上述整個服務閉環設計可以看出,“大秒”的功能完全可以抽象成限流系統,只有在處理搶購活動時,數據的管理與一致性要求才使整個系統變得複雜。

2015年米粉節,我們完全使用大秒的限流功能,不限用戶的購買數量,很便捷的將系統部署在兩個機房,一個物理機房,一個公有云集羣,兩者同時服務,大秒系統作爲整個商城的最前端,能夠根據後端服務的壓力狀態,瞬時調整整個集羣放行流量大小,非常好的保障了整個米粉節的正常舉行。

正如您看到在上述文章中介紹的那樣,這些服務設計的每一次優化的背後,都至少有一次慘痛的經歷,針對這些經歷,我們也做了大量的總結,這些總結將在下兩節的內容裏進行總結性地分享。

10、“大秒”系統架構的幾點經驗總結

10.1 Golang GC 優化方法

我們從 golang 1.2 版本開始在線上搶購系統中大規模使用,最初上線的 TC 限流集羣在搶購的過程中通過過載重啓的方式瘸腿前行。

在當前的大秒系統中,對於限流集羣主要是 goroutine 資源、HTTP 協議數據結構、TCP 連接讀寫緩衝區等頻繁動態開銷,造成內存 GC 壓力大。

在現有 GC 能力下,我們對 GC 優化從以下幾個方面考慮:

1)減少垃圾產生:降低數據結構或者緩衝區的開銷;

2)手動管理內存:使用內存池,手動管理內存;

3)髒數據儘快釋放,增大空閒內存比。

我們使用了以下 3 種 golang GC 優化方法。

1)定製 golang HTTP 包:

調整 HTTP 協議 conn 數據結構默認分配讀寫緩衝區的大小,以及手動維護讀寫緩存池,減少動態開闢內存的次數,降低 GC 壓力。

在 Go 語言原生的 HTTP 包中會爲每個請求默認分配 8KB 的緩衝區,讀、寫緩衝區各 4K。而在我們的服務場景中只有 GET 請求,服務需要的信息都包含在 HTTP header 中,並沒有 body,實際上不需要如此大的內存進行存儲,所以我們調小了讀寫緩衝區,將讀緩衝區調小到 1K,寫緩衝區調小到 32B,golang 的 bufio 在寫緩衝區較小時,會直接寫出。

從 golang 1.3 開始,HTTP 原生的包中已經使用了sync.Pool 維護讀寫緩存池,但是 sync.Pool 中的數據會被自動的回收,同樣會小量的增加 GC 壓力,我們此處自己維護緩存池來減少垃圾回收。

2)加快資源釋放:

原生的 HTTP 包默認使用 keep-alive 的方式,小米搶購場景下,惡意流量佔用了大量的連接,我們通過主動設置 response header 的 connection 爲 close 來主動關閉惡意連接,加快 goroutine 資源的釋放。

3)升級版本:

跟進使用 golang 最新的版本,golang 後續的每個版本都有針對 GC 能力的調整。

得益於開源技術力量,以及大秒系統在 GC 優化上的努力,以及系統層的調優,我們的 HTTP 限流層已經可以餘量前行。

 

從上圖可以看出,得益於 GC 的優化,2015 年米粉節,每輪搶購,HTTP 服務的內存不會有特別大的抖動。

10.2 HTTP 服務器內存調優之操作系統參數調整

我們的服務場景下絕大多數的請求數都是惡意請求,惡意請求通常都是短連接請求,大量的短連接會處於 timewait 狀態,幾分鐘之後纔會釋放,這樣會佔用大量的資源,通過調整內核參數,儘快釋放或者重用 timewait 狀態的連接,減少資源的開銷。

具體參數調整如下:

net.ipv4.tcp_tw_recycle = 1 (打開TIME-WAIT sockets快速回收)

net.ipv4.tcp_tw_reuse = 1 (允許TIME-WAIT sockets複用)

net.ipv4.tcp_max_tw_buckets=10000  (降低系統連接數和資源佔用,默認爲18w)

高併發場景下,操作系統層網絡模塊參數的調整,會起到事半功倍的效果。

10.3 沒有通信就談不上分佈式系統

整個大秒系統模塊之間面臨的通信要求是非常苛刻的,Master 節點與 HTTP、Middle 節點要頻繁的廣播控制命令,dcacenter要實時的收集 HTTP、Middle 節點的監控管理數據,HTTP 要將用戶的購買請求路由到 Middle 節點之間,Middle 節點要返回給相應的 HTTP 節點放號信息;

我們基於 TCP 定製了簡單、高效的通信協議,對於 HTTP 層和 Middle 層通信,通信模塊能夠合併用戶請求,減少通信開銷,保障整個大秒系統的高效通信,增加服務的處理能力。

10.4 服務閉環設計

從上述搶購的服務閉環架構中可以看出,整個搶購流程處理bigtap系統之外,還有 cart 服務,中心 counter 服務,這三者與 bigtap 系統構成了一個數據流的閉環,但是在大秒最初的設計中,是沒有 counter 服務的,Middle層策略集羣在放號的同時,又作爲計數服務存在,但是整個搶購流程卻是以商品加入購物車代表最終的搶購成功,這在設計上有一個漏洞,假如 bigtap 計數了,但是token 並沒有請求加購物車成功,這是不合理的。爲了保證整個系統的準確性,我們增加了計數器服務,計數操作發生在加購物車下游,bigtap 在從計數中心取出商品實時銷量,由此,構成一個服務閉環設計。在提升了系統的準確性,同時也保證了用戶體驗。

10.5 技術的選擇要可控

我們一開始選擇使用 ZooKeeper 存放商品的配置信息,在搶購活動的過程伴隨着大量的配置變更操作,ZooKeeper 的 watch 機制不適合用於頻繁寫的場景,造成消息丟失,大秒前端集羣狀態與配置不一致。

後來,我們將所有的配置信息存放在 Redis 中,基於通信模塊,在發生配置變更時,伴隨着一次配置項變更的廣播通知,大秒前端根據相應的通知命令,拉取 Redis 中相應的配置信息,變更內存中配置及狀態。

11、“大秒”的幾點設計原則

在設計“大秒”的過程中,我們總結了下面這些原則:

1)分治是解決複雜問題的通則:我們從第一代搶購系統演進到當前的大秒系統,衍生出了很多服務,每個服務的產生都是爲了專門解決一個問題,分離整個複雜系統,針對每個服務需要解決的問題,各個擊破,重點優化。由此,才保障了秒殺體系整體性能、可靠性的提升;

2)服務化設計:系統解耦,增強系統的伸縮性與可靠性;

3)無狀態設計:增強系統的伸縮性,提升集羣整體處理能力;

4)狀態數據局部化:相對於數據中心化,提升集羣整體處理能力;

5)中心化監控管理、熱備部署:既保證了服務的高可用性,又能夠提升開發和管理效率。隨着集羣規模的增大以及管理數據的增多,分離管理信息到不同的數據管理節點,實現管理能力的擴容。通常情況下,中小型分佈式系統,單機管理能力即可滿足;

6)避免過度設計、過早的優化:小步快跑,頻繁迭代;

7)沒有華麗的技術,把細小的點做好:不迴避問題,特別是在高併發系統中,一個細小的問題,都可以引發整個服務雪崩。

12、Q&A

1)實時倉庫怎麼避免超賣?

我們的搶購系統以加入購物車代表購買成功,因爲用戶要買配件等,庫存是由計數器控制的,先限流,在計數,在可控的併發量情況下,不會出現超賣。

2)有了放號系統計算放號規則,爲什麼還需要一個外圍的 counter?

主要是 bigtap 到 cart 的環節 token 有丟失,在 cart 之後再加一個計數器,保障銷量,bigtap 再讀取計數器的數據控制前端商品銷售狀態,整個延遲不超 3s。

3)HTTP 集羣通過 uuid hash 到 Middle,如果目標 Middle 已經死掉怎麼應對?

這個問題在文章中有強調,在我們的場景下,商品迅速賣完,這塊沒有做高可用,只是從代碼層面做 review,完善異常處理機制,並且通常情況下,middle 負載不是特別高,幾百次活動下來,還沒出現過掛掉情況。

4)防刷系統是離線計算的嗎,還是有在線識別的策略?

基於日誌,準實時,因爲請求量比較大,專門搭了一套 Kafka 服務轉儲日誌,基於 golang 開發 logcollect 與 antiblack 模塊,可以達到很高的處理性能。

5)請問如何模擬大量請求做測試?

我們遇到的情況是,由於壓測機單機端口限製造成早期不好測試,我們這邊壓測團隊基於開源模塊開發了能夠模擬虛擬IP的模塊,打破了單機端口的限制。

6)即使廣播和 Redis 拉取商品配置信息,仍有可能配置信息不一致如何解決?

這個主要是商品的配置和狀態信息,不涉及到強一致性要求的場景,我們這樣可以在秒級達到最終一致性。

附錄:更多架構設計方面的文章

[1] 有關IM架構設計的文章:

淺談IM系統的架構設計

簡述移動端IM開發的那些坑:架構設計、通信協議和客戶端

一套海量在線用戶的移動端IM架構設計實踐分享(含詳細圖文)

一套原創分佈式即時通訊(IM)系統理論架構方案

從零到卓越:京東客服即時通訊系統的技術架構演進歷程

蘑菇街即時通訊/IM服務器開發之架構選擇

騰訊QQ1.4億在線用戶的技術挑戰和架構演進之路PPT

微信後臺基於時間序的海量數據冷熱分級架構設計實踐

微信技術總監談架構:微信之道——大道至簡(演講全文)

如何解讀《微信技術總監談架構:微信之道——大道至簡》

快速裂變:見證微信強大後臺架構從0到1的演進歷程(一)

17年的實踐:騰訊海量產品的技術方法論

移動端IM中大規模羣消息的推送如何保證效率、實時性?

現代IM系統中聊天消息的同步和存儲方案探討

IM開發基礎知識補課(二):如何設計大量圖片文件的服務端存儲架構?

IM開發基礎知識補課(三):快速理解服務端數據庫讀寫分離原理及實踐建議

IM開發基礎知識補課(四):正確理解HTTP短連接中的Cookie、Session和Token

WhatsApp技術實踐分享:32人工程團隊創造的技術神話

微信朋友圈千億訪問量背後的技術挑戰和實踐總結

王者榮耀2億用戶量的背後:產品定位、技術架構、網絡方案等

IM系統的MQ消息中間件選型:Kafka還是RabbitMQ?

騰訊資深架構師乾貨總結:一文讀懂大型分佈式系統設計的方方面面

以微博類應用場景爲例,總結海量社交系統的架構設計步驟

快速理解高性能HTTP服務端的負載均衡技術原理

子彈短信光鮮的背後:網易雲信首席架構師分享億級IM平臺的技術實踐

知乎技術分享:從單機到2000萬QPS併發的Redis高性能緩存實踐之路

IM開發基礎知識補課(五):通俗易懂,正確理解並用好MQ消息隊列

微信技術分享:微信的海量IM聊天消息序列號生成實踐(算法原理篇)

微信技術分享:微信的海量IM聊天消息序列號生成實踐(容災方案篇)

新手入門:零基礎理解大型分佈式架構的演進歷史、技術原理、最佳實踐

一套高可用、易伸縮、高併發的IM羣聊架構方案設計實踐

阿里技術分享:深度揭祕阿里數據庫技術方案的10年變遷史

阿里技術分享:阿里自研金融級數據庫OceanBase的艱辛成長之路

>> 更多同類文章 ……

[2] 更多其它架構設計相關文章:

騰訊資深架構師乾貨總結:一文讀懂大型分佈式系統設計的方方面面

快速理解高性能HTTP服務端的負載均衡技術原理

子彈短信光鮮的背後:網易雲信首席架構師分享億級IM平臺的技術實踐

知乎技術分享:從單機到2000萬QPS併發的Redis高性能緩存實踐之路

新手入門:零基礎理解大型分佈式架構的演進歷史、技術原理、最佳實踐

阿里技術分享:深度揭祕阿里數據庫技術方案的10年變遷史

阿里技術分享:阿里自研金融級數據庫OceanBase的艱辛成長之路

達達O2O後臺架構演進實踐:從0到4000高併發請求背後的努力

優秀後端架構師必會知識:史上最全MySQL大表優化方案總結

小米技術分享:解密小米搶購系統千萬高併發架構的演進和實踐

>> 更多同類文章 ……

(本文同步發佈於:http://www.52im.net/thread-2323-1-1.html

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