關於秒殺場景的全面分析總結

1.技術層面

1.高訪問壓力隔離
將秒殺系統獨立部署,甚至使用獨立域名,使其與網站完全隔離。

2.用戶在秒殺開始前,通過不停刷新瀏覽器頁面以保證不會錯過秒殺.但是持續刷新商品頁面詳情頁會對服務器造成壓力
重新設計秒殺商品頁面,不使用網站原來的商品詳細頁面,頁面內容靜態化(靜態在CDN或客戶端),用戶請求不需要經過應用服務。而是靜態頁面,秒殺按鈕在秒殺開始前無法點擊。

3.突然增加的網絡帶寬:主要是很多商品的靜態圖片如果從某一個服務器去加載,網頁必然在秒殺開始的那一刻崩潰。
秒殺商品頁面緩存在CDN

4.如果下單的url可以直接通過html源碼獲取,那麼就會有部分用戶繞過網頁前端直接在秒殺開始前下單。

隱藏下單的url,流程變爲了:點擊下單->獲取秒殺url->通過url下單
在獲取url層加入驗證,判斷是否有在下單時間內,如果可以下單就生成隨機數,在url下單時就可以通過隨機數判斷了。

爲了增大qps,獲取秒殺url的時候可以單獨隔離爲其他服務,結果寫入redis(前綴+userId+goodsId,隨機數)即可。

5.如何只允許第一個提交的訂單被髮送到訂單子系統
由於最終能夠成功秒殺到商品的用戶只有一個,因此需要在用戶提交訂單時,檢查是否已經有訂單提交。
如果已經有訂單提交成功,則需要更新 JavaScript文件的請求秒殺url爲空,更新秒殺開始標誌爲否,購買按鈕變灰。

6.限流
在獲取秒殺url這一層可以做限流操作,比如使用guava做令牌桶算法等等。某一個多次點擊秒殺按鈕,會生成驗證碼來限流。

7.減庫存的時機
有兩種選擇,一種是拍下減庫存 另外一種是付款減庫存;目前採用的“拍下減庫存”的方式,拍下就是一瞬間的事,對用戶體驗會好些。

8.庫存會帶來“超賣”的問題
redis分佈式樂觀鎖,如果併發量不算極大也可以考慮zookeeper分佈式鎖

2.設計原則

1.儘量將請求攔截在系統上游
傳統秒殺系統之所以掛,請求都壓倒了後端數據層,數據讀寫鎖衝突嚴重,併發高響應慢,幾乎所有請求都超時,流量雖大,下單成功的有效流量甚小

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

3.架構

在秒殺開始的時候搶先進入下單頁面,而不是商品詳情等用戶體驗細節,因此秒殺系統的頁面設計應儘可能簡單。

下單表單也儘可能簡單,購買數量只能是一個且不可以修改,送貨地址和付款方式都使用用戶默認設置,沒有默認也可以不填,允許等訂單提交後修改

1.前端頁面
加上其他的css, js,圖片等資源,如果同時有幾千萬人蔘與一個商品的搶購,一般機房帶寬也就只有1G10G,所以必須前端頁面CDN。

2.出於性能原因這個一般由js調用客戶端本地時間,就有可能出現客戶端時鐘與服務器時鐘不一致,另外服務器之間也是有可能出現時鐘不一致。

客戶端與服務器時鐘不一致可以採用客戶端定時和服務器同步時間。

這裏考慮一下性能問題,用於同步時間的接口由於不涉及到後端邏輯,只需要將當前web服務器的時間發送給客戶端就可以了,因此速度很快。

並且web服務器羣是可以很容易的橫向擴展的(LB+DNS輪詢),這個接口可以只返回一小段json格式的數據

而且可以優化一下減少不必要cookie和其他http頭的信息,所以數據量不會很大。

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

3.站點設計
前端層的請求攔截,只能攔住小白用戶(不過這是99%的用戶喲),高端的程序員根本不喫這一套,寫個for循環,直接調用你後端的http請求,怎麼整?

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

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

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

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

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

訪問數據庫的過程:秒殺開始->redis->進入消息對列->mysql

對於寫請求,做請求隊列,每次只透過有限的寫請求去數據層,如果均成功再放下一批,如果庫存不夠則隊列裏的寫請求全部返回“已售完”(無需再次訪問數據庫);

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

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

5.請求分發
用戶請求分發模塊:使用Nginx或Apache將用戶的請求分發到不同的機器上

用戶請求預處理模塊:判斷商品是不是還有剩餘來決定是不是要處理該請求。

用戶請求處理模塊:把通過預處理的請求封裝成事務提交給數據庫,並返回是否成功。

數據庫接口模塊:該模塊是數據庫的唯一接口,負責與數據庫交互,提供RPC接口供查詢是否秒殺結束、剩餘數量等信息。

4.數據庫設計

1.數據庫分片
在這裏插入圖片描述
分片解決的是“數據量太大”的問題,也就是通常說的“水平切分”。

一旦引入分片,勢必有“數據路由”的概念,哪個數據訪問哪個庫。

hash分庫:
優點:簡單,數據均衡,負載均勻
缺點:遷移麻煩(2庫擴3庫數據要遷移)

ps:此時不能使用id自增的模式
兩個寫庫使用不同的初始值,相同的步長來增加id:1寫庫的id爲0,2,4,6…;2寫庫的id爲1,3,5,7…;

不使用數據的id,業務層自己生成唯一的id(雪花算法),保證數據不衝突;

2.分組
在這裏插入圖片描述
也就是組從分離模式,一主多從實現讀寫分離

實際互聯網公司都是:分片又分組
在這裏插入圖片描述
3.高可用
在這裏插入圖片描述
仍是雙主,但只有一個主提供服務(讀+寫),另一個主是“shadow-master”,只用來保證高可用,平時不提供服務。

4.讀性能
添加索引,主庫不加索引,從庫加索引
在這裏插入圖片描述

常見的是下面兩種緩存增加讀性能的結構:
在這裏插入圖片描述
在這裏插入圖片描述
5.數據一致性
**主從一致性:**常用中間件同步主從庫,某一個操作會被髮送給所有db。
在這裏插入圖片描述

cache和數據庫的一致性的問題
在這裏插入圖片描述
常見的緩存架構如上,此時寫操作的順序是:

(1)淘汰cache;
(2)寫數據庫;

讀操作的順序是:

(1)讀cache,如果cache hit則返回;
(2)如果cache miss,則讀從庫;
(3)讀從庫後,將數據放回cache;

在一些異常時序情況下,有可能從【從庫讀到舊數據(同步還沒有完成),舊數據入cache後】,數據會長期不一致。解決辦法是“緩存雙淘汰”,寫操作時序升級爲:

(1)淘汰cache;
(2)寫數據庫;
(3)在經過“主從同步延時窗口時間”後,再次發起一個異步淘汰cache的請求;

這樣,即使有髒數據如cache,一個小的時間窗口之後,髒數據還是會被淘汰。帶來的代價是,多引入一次讀miss(成本可以忽略)。

除此之外,最佳實踐之一是:建議爲所有cache中的item設置一個超時時間。

數據庫擴容保證高效擴容:數據庫節點加倍(解決hash擴容的缺點)

原始結構:兩個master,一個作爲另一個的備份,原來只有模0和模1的區別。
在這裏插入圖片描述
開始擴容:現在變成了模0到模3,並且原來的備用的master生效開始工作,承擔四分之一的工作。
在這裏插入圖片描述
最後給四個master分配一個“備用master”。
在這裏插入圖片描述

5.一些總結

萬一負載過大,可以選擇拒絕請求來保護服務的可用性
在這裏插入圖片描述
多次重複的用戶請求生效一次
在這裏插入圖片描述
萬一流量多大以可使用驗證碼來削峯
在這裏插入圖片描述
超發和超賣問題可以使用redis和zookeeper的分佈式鎖解決:
友情鏈接https://blog.csdn.net/qq_35688140/article/details/100983288

精簡至(加入了一些個人對秒殺的理解):https://mp.weixin.qq.com/s?__biz=MzAwOTE3NDY5OA==&mid=2647908611&idx=1&sn=2bd05e30ed8c1e22bf7928b49360b3d6&chksm=8344eac6b43363d04e5525cea543349d4a324b281bb3d19ce46abd2be43e451b67f3051998ee&mpshare=1&scene=1&srcid=&sharer_sharetime=1569457291296&sharer_shareid=7df625ffbcd223e8cf2361bf11b95c68&key=cd483184e931ac1c2f8fa02a37056991cd712f8b7c08f2857dd2c3a700b17889fdd6e5a1ddc2bcf7d266e6c91266d55c80a358045be32d7f04b0939cc06f381bf2ded19470080d417de790f88ee1202a&ascene=1&uin=MjIyODYyOTkwNQ%3D%3D&devicetype=Windows+10&version=62060833&lang=zh_CN&pass_ticket=TEvIJN2kxnjksbeVWbir%2FnVt3556HgCsJsI4MJHacOlounyrYAq%2B14supvhBdLxB

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