秒殺系統的原則和注意項
做秒殺方案亦是如此,秒殺活動經常會引發高并發、系統宕機和庫存超賣的棘手問題,作為開發者,我們該如何在保證系統穩定性的同時,防止業務風險呢?
本篇聊聊秒殺方案的幾個原則和注意點,腦圖見文末。
原則
縱觀多種秒殺方案,沒有相同的,但是這些方案都遵守了相同的原則。具體原則如下:
(1) 保護數據庫
秒殺場景下,一定要優先保護數據庫,這是重中之重。一旦數據庫宕機,那系統徹底癱瘓,會給業務和口碑造成損失。保護數據庫要注意如下幾點:
- 在應用層需要將不合格的請求全部攔截,避免邏輯觸達到數據庫。
- 評估并發數,QPS等,給應用設置合理的數據庫連接池數量,避免將數據庫的連接耗盡。
- 監控數據庫,觀測數據庫的CPU、內存等壓力,觀測慢SQL等,一旦出現問題,及時作出響應。
(2) 保護應用系統
應用系統也是要保護的對象,不管是單體還是微服務,系統盡量不宕機。保護系統要注意這幾點:
- 如果有條件的話,將秒殺系統的BFF層做成獨立的服務,這樣就算本服務掛了,也不影響別的服務。
- 評估秒殺活動的訪問量,適當擴大部分微服務的負載數量,從而提高系統的響應能力。
(3) 提前退出
秒殺系統一旦對外開放,肯定會招來不少羊毛黨,甚至惡意攻擊。所以,在處理邏輯時,一定要做前置校驗,一旦發現非法請求,直接中斷。
如果有條件的話,也要做一些攻擊型測試和壓力測試,看看能否攔住非法請求,看看系統能否承受住壓力。
(4) 不超賣
秒殺場景下的商品,一般都是賠本賺吆喝,真的是賣一單虧一單。一般秒殺的商品、價格、庫存,都是公司的運營和管理層溝通確認的結果。
為了將虧損控制在合理的范圍,要嚴格按照既定的庫存去售賣,一定不能出現超賣的情況。
前端主要注意點
秒殺場景下,前端有一些注意點,如下:
- 頁面靜態化:不管是在PC、H5、小程序還是APP,頁面盡量靜態化,能走緩存的走緩存,盡量少的去請求接口。
- CDN:將涉及到的js、圖片、html等靜態資源,提前刷到CDN中,加快訪問速度。
- 從緩存讀取數據:秒殺場景下用到的接口要和常規接口區分開,秒殺場景下的接口盡量是從Redis緩存中讀取數據,然后響應給前端。前端也需要判斷哪些數據可以存入前端緩存中,避免下次重復調接口獲取。
- 前端做攔截:前端頁面也要做一些攔截動作,過濾非法請求。雖然作用不大,只防君子不防小人,但是也要做。一切能提前攔截掉非法請求的動作,都要做。
后端主要注意點
后端的注意事項較多,大致如下:
(1) 彈性增加服務器:根據自身的整體部署情況,適當擴大負載。比如混合云部署的方式,可以按需臨時租用幾臺云廠商的云服務器,等活動結束立馬釋放云服務器,這樣成本最小。
(2) 限流和降級:不管是在秒殺場景,還是其余場景,保護系統的手段就是限流、降級、熔斷。不管擱在什么時候,都是這三板斧。
(3) 前置校驗:前置校驗可以最大程度的攔住非法請求。比如校驗惡意的重復IP、校驗用戶的重復下單、校驗庫存等等。
(4) 緩存預熱:對于秒殺的商品信息和庫存,需要提前做緩存預熱,比如將數據提前刷到Redis緩存中。
(5) 定時任務:
- 及時釋放庫存:一般場景下,可能半小時才會取消未支付的訂單。但在秒殺場景下,由于庫存有限,避免惡意占庫存,所以允許訂單未支付的時間就要減少,比如3分鐘。這種場景下,可以用定時任務及時取消訂單,或者,采用消息隊列的定時消息方案(比如RocketMQ的延遲消息)。
- 校準緩存的庫存:下單會占用庫存,取消訂單會釋放庫存。如果庫存預熱到了Redis,則需要有個定時任務去校準Redis里的庫存數量。
(6) 下單和減庫存:
- 樂觀鎖減庫存:更新數據庫里的庫存數量時,一定要使用樂觀鎖方案去避免超賣,類似update ttt set stock = xxx where product_id = yyy and stock = zzz;。
- 同步或異步:在走完前置邏輯后,則會進入到下單和減庫存邏輯,此時,可以用同步方式直接調用,也可以用異步丟入到MQ的方式。具體采用哪種方式,需要根據系統的吞吐量去做評估。
總結
本文主要聊了秒殺方案的幾個原則和前后端注意事項。方案千千萬,原則就這么幾個。最后,貼上一張腦圖方便記憶。