秒殺系統的原則和注意項

做秒殺方案也是如此,秒殺活動經常會引發高並發、系統宕機和庫存超賣的棘手問題,作為開發者,我們該如何在確保系統穩定性的同時,防止業務風險呢?

本篇聊聊秒殺方案的幾個原則和注意點,腦圖見文末。

原則

縱觀多種秒殺方案,沒有相同的,但是這些方案都遵守了相同的原則。具體原則如下:

(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的方式。具體採用哪種方式,需要根據系統的吞吐量去做評估。

總結

本文主要聊了秒殺方案的幾個原則和前後端注意事項。方案千千萬,原則就這麼幾個。最後,貼上腦圖方便記憶。