阿里秒殺系統架構優化思路

秒殺業務爲什麼難做阿里秒殺系統架構優化思路

  • im系統,例如qq或者微博,每個人都讀自己的數據(好友列表、羣列表、個人信息)
  • 微博系統,每個人讀你關注的人的數據,一個人讀多個人的數據
  • 秒殺系統,庫存只有一份,所有人會在集中的時間讀和寫這些數據,多個人讀一個數據
    例如:小米手機每週二的秒殺,可能手機只有1萬部,但瞬時進入的流量可能是幾百幾千萬。

又例如:12306搶票,票是有限的,庫存一份,瞬時流量非常多,都讀相同的庫存。讀寫衝突,鎖非常嚴重,這是秒殺業務難的地方。那我們怎麼優化秒殺業務的架構呢?
阿里秒殺系統架構優化思路

優化方向

優化方向有兩個(今天就講這兩個點):

(1)將請求儘量攔截在系統上游(不要讓鎖衝突落到數據庫上去)。傳統秒殺系統之所以掛,請求都壓倒了後端數據層,數據讀寫鎖衝突嚴重,併發高響應慢,幾乎所有請求都超時,流量雖大,下單成功的有效流量甚小。以12306爲例,一趟火車其實只有2000張票,200w個人來買,基本沒有人能買成功,請求有效率爲0。

(2)充分利用緩存,秒殺買票,這是一個典型的讀多些少的應用場景,大部分請求是車次查詢,票查詢,下單和支付纔是寫請求。一趟火車其實只有2000張票,200w個人來買,最多2000個人下單成功,其他人都是查詢庫存,寫比例只有0.1%,讀比例佔99.9%,非常適合使用緩存來優化。好,後續講講怎麼個“將請求儘量攔截在系統上游”法,以及怎麼個“緩存”法,講講細節。

常見秒殺架構

常見的站點架構基本是這樣的(絕對不畫忽悠類的架構圖)
阿里秒殺系統架構優化思路

  1. 瀏覽器端,最上層,會執行到一些JS代碼
  2. 站點層,這一層會訪問後端數據,拼html頁面返回給瀏覽器
  3. 服務層,向上遊屏蔽底層數據細節,提供數據訪問
  4. 數據層,最終的庫存是存在這裏的,mysql是一個典型(當然還有會緩存)
    這個圖雖然簡單,但能形象的說明大流量高併發的秒殺業務架構,大家要記得這一張圖。

後面細細解析各個層級怎麼優化。

各層次優化細節

第一層,客戶端怎麼優化(瀏覽器層,APP層)

問大家一個問題,大家都玩過微信的搖一搖搶紅包對吧,每次搖一搖,就會往後端發送請求麼?回顧我們下單搶票的場景,點擊了“查詢”按鈕之後,系統那個卡呀,進度條漲的慢呀,作爲用戶,我會不自覺的再去點擊“查詢”,對麼?繼續點,繼續點,點點點。。。有用麼?平白無故的增加了系統負載,一個用戶點5次,80%的請求是這麼多出來的,怎麼整?

(a)產品層面,用戶點擊“查詢”或者“購票”後,按鈕置灰,禁止用戶重複提交請求;

(b)JS層面,限制用戶在x秒之內只能提交一次請求;

APP層面,可以做類似的事情,雖然你瘋狂的在搖微信,其實x秒才向後端發起一次請求。這就是所謂的“將請求儘量攔截在系統上游”,越上游越好,瀏覽器層,APP層就給攔住,這樣就能擋住80%+的請求,這種辦法只能攔住普通用戶(但99%的用戶是普通用戶)對於羣內的高端程序員是攔不住的。firebug一抓包,http長啥樣都知道,js是萬萬攔不住程序員寫for循環,調用http接口的,這部分請求怎麼處理?

第二層,站點層面的請求攔截

怎麼攔截?怎麼防止程序員寫for循環調用,有去重依據麼?ip?cookie-id?…想複雜了,這類業務都需要登錄,用uid即可。在站點層面,對uid進行請求計數和去重,甚至不需要統一存儲計數,直接站點層內存存儲(這樣計數會不準,但最簡單)。一個uid,5秒只准透過1個請求,這樣又能攔住99%的for循環請求。

5s只透過一個請求,其餘的請求怎麼辦?緩存,頁面緩存,同一個uid,限制訪問頻度,做頁面緩存,x秒內到達站點層的請求,均返回同一頁面。同一個item的查詢,例如車次,做頁面緩存,x秒內到達站點層的請求,均返回同一頁面。如此限流,既能保證用戶有良好的用戶體驗(沒有返回404)又能保證系統的健壯性(利用頁面緩存,把請求攔截在站點層了)。

頁面緩存不一定要保證所有站點返回一致的頁面,直接放在每個站點的內存也是可以的。優點是簡單,壞處是http請求落到不同的站點,返回的車票數據可能不一樣,這是站點層的請求攔截與緩存優化。

好,這個方式攔住了寫for循環發http請求的程序員,有些高端程序員(***)控制了10w個肉雞,手裏有10w個uid,同時發請求(先不考慮實名制的問題,小米搶手機不需要實名制),這下怎麼辦,站點層按照uid限流攔不住了。

第三層 服務層來攔截(反正就是不要讓請求落到數據庫上去)

服務層怎麼攔截?大哥,我是服務層,我清楚的知道小米只有1萬部手機,我清楚的知道一列火車只有2000張車票,我透10w個請求去數據庫有什麼意義呢?沒錯,請求隊列!

對於寫請求,做請求隊列,每次只透有限的寫請求去數據層(下訂單,支付這樣的寫業務)

1w部手機,只透1w個下單請求去db

3k張火車票,只透3k個下單請求去db

如果均成功再放下一批,如果庫存不夠則隊列裏的寫請求全部返回“已售完”。

對於讀請求,怎麼優化?cache抗,不管是memcached還是redis,單機抗個每秒10w應該都是沒什麼問題的。如此限流,只有非常少的寫請求,和非常少的讀緩存mis的請求會透到數據層去,又有99.9%的請求被攔住了。

當然,還有業務規則上的一些優化。回想12306所做的,分時分段售票,原來統一10點賣票,現在8點,8點半,9點,...每隔半個小時放出一批:將流量攤勻。

其次,數據粒度的優化:你去購票,對於餘票查詢這個業務,票剩了58張,還是26張,你真的關注麼,其實我們只關心有票和無票?流量大的時候,做一個粗粒度的“有票”“無票”緩存即可。

第三,一些業務邏輯的異步:例如下單業務與 支付業務的分離。這些優化都是結合 業務 來的,我之前分享過一個觀點“一切脫離業務的架構設計都是耍流氓”架構的優化也要針對業務。

好了,最後是數據庫層

瀏覽器攔截了80%,站點層攔截了99.9%並做了頁面緩存,服務層又做了寫請求隊列與數據緩存,每次透到數據庫層的請求都是可控的。db基本就沒什麼壓力了,閒庭信步,單機也能扛得住,還是那句話,庫存是有限的,小米的產能有限,透這麼多請求來數據庫沒有意義。

全部透到數據庫,100w個下單,0個成功,請求有效率0%。透3k個到數據,全部成功,請求有效率100%。
阿里秒殺系統架構優化思路
阿里秒殺系統架構優化思路
總結

對於秒殺系統,我個人經驗有兩個架構優化思路:

(1)儘量將請求攔截在系統上游(越上游越好);

(2)讀多寫少的常用多使用緩存(緩存抗讀壓力);

瀏覽器和APP:做限速

站點層:按照uid做限速,做頁面緩存

服務層:按照業務做寫請求隊列控制流量,做數據緩存

數據層:閒庭信步

並且:結合業務做優化

那如何學習才能快速入門並精通呢?

當真正開始學習的時候難免不知道從哪入手,導致效率低下影響繼續學習的信心。

但最重要的是不知道哪些技術需要重點掌握,學習時頻繁踩坑,最終浪費大量時間,所以有一套實用的視頻課程用來跟着學習是非常有必要的。

爲了讓學習變得輕鬆、高效,今天給大家免費分享一套阿里的Java架構師傳授的一套教學資源。幫助大家在成爲架構師的道路上披荊斬棘。

這套視頻課程,詳細講解了像(Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構)等這些成爲架構師必備的內容!

而且還把框架需要用到的各種程序進行了打包,根據基礎視頻可以讓你輕鬆搭建分佈式框架環境,像在企業生產環境一樣進行學習和實踐。在此我向大家推薦一個Java架構交流羣:687107762阿里秒殺系統架構優化思路

最後,做一個愛思考,懂思考,會思考的程序員。

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