秒殺系統中的扣減庫存和流量削峰

王子發表於2020-09-17

 

前言

上篇文章我們一起討論了秒殺系統下,通過堆加機器解決高併發的方案有什麼缺點,又討論了使用多級快取架構構建靜態化頁面,來減輕前端頁面伺服器壓力的方式。

今天我們就接著往下討論,小夥伴們可以看一下上一篇文章做個複習,討論一下秒殺系統的技術難點與解決方案

我們先回顧一下場景。

假如我們的系統在00:00有一場秒殺活動,那麼會有大量使用者會提前幾分鐘開始重新整理頁面,這部分的解決方案上篇文章已經提出。

緊接著就是到了00:00之後,頁面上可能會出現一個按鈕,大量使用者就會通過點選按鈕開始向後臺傳送請求,搶購商品。

搶購到之後還要有下訂單、支付、減庫存等後續一系列的流程,所以不對這些操作進行優化,直接運算元據庫,系統的壓力一定是很大的。

接下來我們就針對這個問題一起看看如何解決吧。

 

驗證使用者身份

首先我們思考一個問題,對於秒殺活動,會不會有人作弊呢?

比如寫好一段程式碼,在秒殺活動開始之前就不停的迴圈重新整理頁面,搶購商品。

王子告訴大家,這種情況是一定會發生的。其實我們看看各種搶票軟體就明白了,每次高峰期搶票不也會有很多的渠道去刷票嗎,這麼看來12306能支援這麼多的併發確實做得還不錯。

那麼如何針對這種作弊的行為呢,其實我們可以在秒殺成功之後做一個驗證使用者身份的功能,保證你是人而不是程式碼。

方式可以是彈出框做個驗證碼驗證,或者做個答題功能,需要人工答對之後才能進行下一步的操作。

這個辦法是非常有效的,不僅可以對作弊行為進行過濾,而且每個人回答的速度是不一樣的,所以使用者發起的請求就不會全部的積壓在一個時間點上。

 

獨立的秒殺系統叢集

身份驗證過後,使用者就會把大量的請求傳送到我們的訂單系統中,那麼問題來了,在秒殺活動中發起的海量請求,是要發給我們平時執行時使用的同一個訂單系統叢集中嗎?

我們來思考一個問題,假如秒殺業務和平時的業務使用的是一套訂單系統叢集,那麼在秒殺活動的時候,可能有海量的使用者來參加秒殺活動,但是同樣也有不會參加秒殺活動的使用者在同時訂購商品。

那麼當秒殺開始的時候,訂單伺服器壓力會劇增,普通使用者也發起請求到訂單伺服器,這樣會發生什麼呢?

很可能伺服器由於秒殺系統帶來的壓力,效能變差,那麼普通使用者在進行正常的下訂單操作時也會發現系統執行緩慢。

所以我們要單獨部署一套秒殺系統叢集,單獨處理秒殺業務,從而不影響正常業務的效能。

而且單獨的秒殺系統叢集也更容易做一些特殊的架構優化,說到這裡,架構圖如下:

 

 

扣減庫存的優化

後臺系統在使用者搶購成功後,應該先做什麼操作呢?

第一步操作就是扣減庫存,因為大家知道,參與秒殺活動的商品都是有數量限制的,所以大量使用者搶購成功後的第一步操作就是扣減庫存。

那麼如何進行扣減庫存的操作呢?

小夥伴們可能會回答,可以在秒殺系統叢集中呼叫庫存系統介面,連線資料庫,更新庫存數量。但這樣一來不就又面臨著資料庫壓力過大的問題了嗎?

其實我們可以在活動開始前,把要秒殺的商品庫存存放到Redis叢集中,然後扣減庫存的時候只操作Redis叢集,就可以大大降低資料庫壓力了。

當商品的庫存扣減完畢之後,使用者傳送過來搶購的請求其實就不必再傳送給秒殺系統了,可以直接在Nginx中過濾掉。

Nginx具體如何過濾呢?這裡王子提出一點思路,我們可以通過Zookeeper來實現。

當商品庫存為0後,我們可以在Zookeeper中設定一個標誌,表名商品已經售空了,同時可以利用Zookeeper的監聽機制,告知Nginx的lua指令碼,然後Lua指令碼直接過濾掉無效的請求,並返回使用者一個“庫存已售空”的響應資訊就可以了。

這樣可以很大幅度的減少海量請求對後臺秒殺系統的壓力。

 

引入RocketMQ進行流量削峰

通過之前的優化,已經過濾掉了大量的無用請求,那麼針對正常參加秒殺,傳送給後臺的請求我們應該怎麼進行架構優化呢?

這個時候我們就可以引入RocketMQ,來進行流量削峰了

也就是說,當使用者傳送請求,經過Redis扣減庫存的操作後發現庫存數量還是大於0的,那麼這個時候就可以把建立訂單的操作傳送訊息給RocketMQ,然後我們平時使用的訂單系統從RocketMQ中限流獲取訊息,進行常規的操作(生成訂單、支付等等)。這樣就不會對資料庫有太大的壓力了。

由於訂單系統限流獲取訊息,所以會造成RockeMQ的訊息積壓問題,但RocketMQ是高可用的叢集,可以保證訊息的不丟失。所以完全可以讓訂單系統每秒幾千條的速度去消費,頂多可能會延遲個幾十秒才會生成訂單而已。

所以我們最後的架構圖如下:

 

總結

到這裡,相信小夥伴們對於秒殺系統的架構方案已經有了一個整體的瞭解了。

其實總結起來,秒殺系統的架構優化核心就是:單獨部署抗下高併發的伺服器叢集,阻止高併發請求訪問資料庫

因為資料庫是整個系統架構中的效能瓶頸,不可能無限擴充套件資料庫伺服器的數量來抗下高併發請求。而且不是所有時候系統都有這麼高的併發的,擴充套件資料庫並不划算。

還有在這裡王子要說明一點,一套完整的秒殺系統架構體系是很複雜的,我們只是通過這麼一個秒殺業務的場景,讓小夥伴們感受到訊息中介軟體在這樣的架構中扮演的角色。

後續的文章裡,我們還會一起深入的探討訊息中介軟體的底層原理,讓我們一起進步吧。

 

 

往期文章推薦:

中介軟體專輯:

什麼是訊息中介軟體?主要作用是什麼?

常見的訊息中介軟體有哪些?你們是怎麼進行技術選型的?

你懂RocketMQ 的架構原理嗎?

聊一聊RocketMQ的註冊中心NameServer

Broker的主從架構是怎麼實現的?

RocketMQ生產部署架構如何設計

RabbitMQ和Kafka的高可用叢集原理

RocketMQ的傳送模式和消費模式

討論一下秒殺系統的技術難點與解決方案

 

相關文章