高併發系統設計十五-消息隊列:秒殺時如何處理每秒上萬次的下單請求

1、場景分析

在項目中遇到一些存在高併發寫請求的場景,例如秒殺搶購。

比如6.18,活動從0:00開始,僅限前 200 名,那秒殺即將開始時,後臺會顯示用戶正在瘋狂的刷新 APP

或者瀏覽器來保證自己能夠儘早的看到商品

對於這種情況,你應該考慮什麼呢?

  • 當秒殺開始前,用戶在不斷的刷新頁面,系統應該如何應對高併發的讀請求呢?
  • 在秒殺開始時,用戶瞬間向系統請求生成訂單,扣減庫存,系統應該如何應對高併發的寫請求呢?

1.1、系統應該如何應對高併發的讀請求

  • 使用緩存策略將請求擋在上層中的緩存中
  • 能靜態化的數據儘量做到靜態化
  • 加入限流(比如對短時間之內來自某一個用戶,某一個IP、某個設備的重複請求做丟棄處理)

1.2、系統應該如何應對高併發的寫請求

生成訂單,扣減扣除,用戶這些操作是不經過緩存直達數據庫的。如果在 1 s 內,有 1 萬個數據連接同時到達,系統的數據庫會瀕臨崩潰。如何解決這個問題呢?我們可以使用 消息隊列

2、消息隊列

消息隊列的作用:

  • 削去秒殺場景下的峯值寫流量
  • 通過異步處理簡化秒殺請求中的業務流程
  • 解耦,實現秒殺系統模塊之間松耦合

2.1、削去秒殺場景下的峯值寫流量

將秒殺請求暫存在消息隊列中,然後業務服務器會響應用戶“秒殺結果正在計算中”,釋放了系統資源之後再處理其它用戶的請求。

削峯填谷,削平短暫的流量高峯,雖說堆積會造成請求被短暫延遲處理,但是隻要我們時刻監控消息隊列中的堆積長度,在堆積量超過一定量時,增加隊列處理機數量來提升消息的處理能力就好了,而且秒殺的用戶對於短暫延遲知曉秒殺的結果也是有一定容忍度的。

秒殺商品有 1000 件,處理一次購買請求的時間是 500ms,那麼總共就需要 500s 的時間。這時你部署 10 個隊列處理程序,那麼秒殺請求的處理時間就是 50s,也就是說用戶需要等待 50s 纔可以看到秒殺的結果,這是可以接受的。這時會併發 10 個請求到達數據庫,並不會對數據庫造成很大的壓力。

2.2、通過異步處理簡化秒殺請求中的業務流程

先處理主要的業務邏輯,採用異步處理次要的業務邏輯。

比如說,主要的流程是生成訂單、扣減庫存;次要的流程可能是我們在下單購買成功之後會給用戶發放優惠券,會增加用戶的積分。

假如發放優惠券的耗時是 500ms,增加用戶積分的耗時也是 500ms,那麼如果我們將發放優惠券、增加積分的操作放在另外一個隊列處理機中執行,那麼整個流程就縮短到了 400ms,性能提升了 20%,處理這 1000 件商品的時間就變成了 400s。如果我們還是希望能在 50s 之內看到秒殺結果的話,只需要部署 8 個隊列程序就好了

2.3、解耦,實現秒殺系統模塊之間松耦合

將秒殺數據同步給數據團隊,有兩種思路:

  • 使用 HTTP 或者 RPC 的方式來同步調用,即提供一個接口,實時將數據推送給數據服務

    • 整體系統的耦合度較高,如果其中一個服務有問題,可能會導致另一個服務不可用
    • 數據服務需要的數據字段如果發生變化,秒殺服務需要同步修改
  • 使用消息隊列

    將數據全部發送給消息隊列,然後數據服務訂閱這個消息隊列,接收到數據。

3、其他問題

引入消息隊列的同時也會引入新的問題,需要新的方案來解決,這就是系統設計的挑戰,也是系統設計獨有的魅力,而我們也會在這些挑戰中不斷提升技術能力和系統設計能力。

  • 同步流程和異步流程的邊界在哪裏?
  • 消息是否會丟失,是否會重複?
  • 請求的延遲如何能夠減少?
  • 消息接收的順序是否會影響到業務流程的正常執行?
  • 如果消息處理流程失敗了之後是否需要補發?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章