'秒殺系統架構優化思路'

"
作者:大坑神
來源:https://yq.aliyun.com/articles/69704
"
作者:大坑神
來源:https://yq.aliyun.com/articles/69704
秒殺系統架構優化思路

一、為什麼秒殺這麼難

秒殺系統難做的原因:庫存只有一份,所有人會在集中的時間讀和寫這些數據。例如小米手機每週二的秒殺,可能手機只有1萬部,但瞬時進入的流量可能是幾百幾千萬。又例如12306搶票,亦與秒殺類似,瞬時流量更甚。

1.1主要需要解決的問題有兩個

1、高併發對數據庫產生的壓力

2、競爭狀態下如何解決庫存的正確減少( 超賣問題)

對於第一個問題,已經很容易想到用緩存來處理搶購,避免直接操作數據庫,例如使用Redis。重點在於第二個問題,常規寫法:

查詢出對應商品的庫存,看是否大於0,然後執行生成訂單等操作,但是在判斷庫存是否大於0處,如果在高併發下就會有問題,導致庫存量出現負數

二、常見架構

瀏覽器--->站點--->服務--->數據

流量到了億級別,常見站點架構如上:

1、瀏覽器端,最上層,會執行到一些JS代碼

2、站點層,這一層會訪問後端數據,拼html頁面返回給瀏覽器

3、服務層,向上遊屏蔽底層數據細節

4、數據層,最終的庫存是存在這裡的,mysql是一個典型

三、優化方向

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

2、充分利用緩存:這是一個典型的 讀多寫少的應用場景【一趟火車其實只有2000張票,200w個人來買,最多2000個人下單成功,其他人都是查詢庫存,寫比例只有0.1%,讀比例佔99.9%】,非常適合使用緩存。

四、優化細節

4.1 瀏覽器層請求攔截

點擊了“查詢”按鈕之後,系統那個卡呀,進度條漲的慢呀,作為用戶,我會不自覺的再去點擊“查詢”,繼續點,繼續點,點點點。。。有用麼?平白無故的增加了系統負載(一個用戶點5次,80%的請求是這麼多出來的),怎麼整?

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

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

如此限流,80%流量已攔

4.2 站點層請求攔截與頁面緩存

瀏覽器層的請求攔截,只能攔住小白用戶(不過這是99%的用戶喲),高端的程序員根本不吃這一套,寫個for循環,直接調用你後端的http請求,怎麼整?

a 同一個uid,限制訪問頻度,做頁面緩存,x秒內到達站點層的請求,均返回同一頁面

b 同一個item的查詢,例如手機車次,做頁面緩存,x秒內到達站點層的請求,均返回同一頁面

如此限流,又有99%的流量會被攔截在站點層

4.3 服務層請求攔截與數據緩存

站點層的請求攔截,只能攔住普通程序員,高級黑客,假設他控制了10w臺肉雞(並且假設買票不需要實名認證),這下uid的限制不行了吧?怎麼整?

a 大哥,我是服務層,我清楚的知道小米只有1萬部手機,我清楚的知道一列火車只有2000張車票,我透10w個請求去數據庫有什麼意義呢? 對於寫請求,做請求隊列,每次只透有限的寫請求去數據層,如果均成功再放下一批,如果庫存不夠則隊列裡的寫請求全部返回“已售完”

b 對於讀請求,還要我說麼?cache抗,不管是memcached還是redis,單機抗個每秒10w應該都是沒什麼問題的

如此限流,只有非常少的寫請求,和非常少的讀緩存mis的請求會透到數據層去,又有99.9%的請求被攔住了

4.4 數據層閒庭信步

到了數據這一層,幾乎就沒有什麼請求了,單機也能扛得住,還是那句話,庫存是有限的,小米的產能有限,透這麼多請求來數據庫沒有意義。

五、總結

沒什麼總結了,上文應該描述的非常清楚了,對於秒殺系統,再次重複下兩個架構優化思路:

1、儘量將請求攔截在系統上游

2、讀多寫少經量多使用緩存

3、Redis隊列緩存 + mysql 批量入庫

"

相關推薦

推薦中...