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

王子發表於2020-09-16

 

前言

小夥伴們,我們先回顧一下,在一個系統中引入訊息中介軟體後會給系統帶來什麼好處呢?

通過之前的文章我們瞭解到,引入MQ後主要可以解決三個問題:非同步、解耦、削峰,小夥伴們可以回顧一下這篇文章什麼是訊息中介軟體?主要作用是什麼?

今天王子就和大家聊一聊削峰的具體場景,針對一個電商系統中,秒殺系統這部分的技術難點與解決方案。

 

系統面臨的瓶頸是什麼

我們先了解一下,秒殺系統中具體有什麼問題需要解決呢?王子給大家畫一張圖:

 

 

假如我們的系統有了秒殺的業務,那麼會有海量的使用者訪問我們的訂單系統叢集,其實這裡還不是技術的瓶頸,只要擴充套件訂單系統叢集,增加訂單系統的機器數量就可以抗下這樣甚至更高的高併發情況。

 

那麼技術瓶頸是什麼呢?

我們再來看資料庫部分,你會發現無論你的訂單系統叢集增加多少機器,它們訪問的還是一個資料庫。那麼每次面對秒殺系統這樣的活動時,資料庫要承受的壓力是極大的,很可能因此當機,導致整個系統崩掉,後果是很可怕的。

由此我們分析出,資料庫是秒殺系統面臨的一大瓶頸。

 

如何解決秒殺系統的瓶頸

剛才我們談到,秒殺系統面臨的技術瓶頸是資料庫,那麼我們如何解決呢?是不是要部署更多的資料庫伺服器,對資料庫進行分庫分表,然後讓更多的資料庫伺服器共同抗下高併發的情況呢?

這種分庫分表的策略是這樣的,假設我們目前操作的是一個庫中的一張訂單表,那麼分庫後就變成了多個庫,每個庫裡都只存一部分的訂單資料,分庫策略可以是按時間戳或者雜湊演算法計算得出(這不是本篇重點,以後會有單獨的資料庫專題討論),分表呢就是可以在一個庫裡對訂單表再次拆分成多張表,資料再次分片儲存。

這種模式有什麼好處呢?

好處其實是顯而易見的,我們的高併發請求可以平均分配到多臺資料庫上,整個的資料庫叢集可以共同承擔高併發帶來的壓力,而且也可以通過擴充套件資料庫叢集實現可以承擔更高併發的能力。

說到這裡,小夥伴們是不是覺得,這個問題就這麼解決了呢?

王子可以明確的告訴大家,這種解決方法是很不靠譜的,除非公司的技術能力太弱,沒有人能搭建出更可靠的架構才會選擇這種下下策,通過堆疊機器數量來抵抗高併發下的壓力。

試著想一下,假如我們的系統很受客戶歡迎,使用者量日漸增長,達到了海量的使用者數,難道我們要不停的增加伺服器數量嗎?

伺服器的成本是不是有點偏高了呢?

所以要解決這個問題,我們的出發點一定要正確,就是不能通過不停的增加機器解決這種問題,而是在有限的資源下設計出更優雅的架構來解決,這樣的方法才是上策。

 

前臺頁面的優化

知道了我們應該在有限資源下進行架構優化,那麼我們先思考一個問題。

使用者參加秒殺活動的時候,是如何作業系統的呢?

就拿雙十一搶購來說,在00:00的時候就是秒殺的時候,那麼很多使用者會提前幾分鐘把手機開啟到對應的頁面,沒到時間就開始不停的重新整理頁面,等待秒殺開始那一刻的到來。

那麼小夥伴們有沒有考慮過,這些要重新整理的頁面都是從哪裡來的呢?

我們的頁面其實也是要有自己專門的訂單頁面伺服器的,主要用於提供前端的訪問頁面,基本結構如下圖:

 

所以,首先接受高併發請求的系統是前端頁面系統。

大家思考一個問題,如果平時不是秒殺的時候,使用者看的商品可能都是不同的,但是一旦有秒殺活動,可能有大量的使用者一起不停的重新整理同一個商品的同一個頁面,對系統造成壓力。

那麼對於這個問題,我們應該怎麼解決呢?

王子今天介紹的解決方案就是頁面資料的靜態化+多級快取的策略。

 

頁面資料靜態化

我們先來聊一聊什麼是頁面資料的動態化。

假設我們的前端頁面是動態化的,那麼使用者每次訪問頁面,都會向頁面系統傳送請求獲取資料,然後前端頁面根據獲取的資料渲染頁面,一般來說系統的演進都是從這種動態化開始的,比如jsp頁面。

那麼如何實現頁面的靜態化呢,其實就是改變頁面獲取資料的方式,每次獲取資料不再是通過頁面系統查詢資料庫而是從別的地方獲取資料,避免每次都去訪問後端資料庫,對系統造成壓力。

 

多級快取

瞭解的靜態化的思想,那麼我們再來看看多級快取是什麼,我們要聊的多級快取指的是CDN+Nginx+Redis的多級快取架構。

什麼意思呢?就是說頁面的資料首先放一份到離使用者最近的CDN上邊。

可能有的小夥伴不理解CDN,王子給大家簡單掃一下盲。

比如我們的系統伺服器部署在北京,訪問我們系統的使用者在海南,那麼它每次訪問我們系統是要到我們北京的伺服器上面獲取資料嗎?

不是的,我們是可以把靜態化的頁面資料部署到海南的CDN上邊去的,而海南的使用者就可以通過CDN獲取到我們系統的頁面資料。

這個CDN都是各種雲廠商提供的服務,它就是我們架構中的第一級快取

如果由於CDN中快取過期等原因,導致沒有從CDN中得到頁面資料,那麼此時使用者就會將這個請求傳送到我們北京的伺服器上邊,但是這個時候系統不是直接查詢資料庫返回資料的,而是先訪問Nginx伺服器上的快取。

Nginx是可以基於Lua指令碼實現本地快取的,我們可以提前吧頁面資料放到Nginx快取中,作為第二級的快取

如果Nginx上邊也沒有想要的資料呢?

那麼此時可以通過Nginx上的lua指令碼傳送請求到Redis叢集中載入資料,Redis叢集就作為我們多級快取架構的第三級快取

如果在Redis叢集中還是沒有找到資料,我們再去從資料庫載入出來,並更新到快取裡。

通過這樣一套多級快取的架構,我們就可以實現頁面的靜態化資料的儲存(資料可能就是一段json串),這樣對於我們的頁面伺服器本身壓力就非常的小了。

架構圖如下:

 

 

總結

今天我們聊了聊高併發系統下,堆積機器方案的弊端,同時也介紹了秒殺場景下面臨的一些技術挑戰。

又講解了使用多級快取架構構建靜態化頁面的方式。

但秒殺系統是一個複雜的系統,深入研究細節是很多的,王子主要是在這裡介紹一下秒殺系統的整體場景,和針對於秒殺系統做的一些架構優化的思路,從而引出如何將RocketMQ落實到秒殺系統中,實現流量的削峰功效。

那麼下篇文章我們就一起聊聊如何將MQ引入到系統中,進行流量削峰的優化吧。

 

 

往期文章推薦:

中介軟體專輯:

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

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

你懂RocketMQ 的架構原理嗎?

聊一聊RocketMQ的註冊中心NameServer

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

RocketMQ生產部署架構如何設計

RabbitMQ和Kafka的高可用叢集原理

RocketMQ的傳送模式和消費模式

演算法專輯:

和同事談談Flood Fill 演算法

詳解股票買賣演算法的最優解(一)

詳解股票買賣演算法的最優解(二)

聊一聊二分查詢法

 

相關文章