從全局角度,如何設(shè)計(jì)一個(gè)秒殺系統(tǒng)?
?大家好,我是樹哥。
秒殺系統(tǒng)的設(shè)計(jì)是高級(jí)職位面試中非常高頻的一道題目,它可以較好地考察候選人的知識(shí)體系情況。對(duì)于我們來說,學(xué)習(xí)秒殺系統(tǒng)的設(shè)計(jì),能夠讓我們學(xué)以致用,設(shè)計(jì)系統(tǒng)的時(shí)候考慮得更加全面。今天就讓樹哥帶你一起來看看怎么設(shè)計(jì)一個(gè)秒殺系統(tǒng)!

活動(dòng)一般出現(xiàn)在電商的促銷活動(dòng)中,一般是指定了很少數(shù)量的商品,以極低的價(jià)格,讓大量的用戶參與,從而造成大量用戶在極短的時(shí)間內(nèi)參與活動(dòng),進(jìn)而造成系統(tǒng)在極短的時(shí)間內(nèi)有極高的流量。系統(tǒng)設(shè)計(jì)的目的是使系統(tǒng)能夠穩(wěn)定地支撐活動(dòng)的進(jìn)行,因此其穩(wěn)定性、高可用是我們考慮的第一位。
要知道如何進(jìn)行秒殺系統(tǒng)的優(yōu)化,那我們需要先對(duì)請(qǐng)求的整個(gè)流程有個(gè)全局的認(rèn)識(shí)。一般來說,秒殺活動(dòng)請(qǐng)求以公網(wǎng)為劃分點(diǎn),可以分為:前端部分、后端部分。 前端部分指的是從用戶端到進(jìn)入后端服務(wù)前的部分,包括了移動(dòng)端的處理、DNS 解析、公網(wǎng)的數(shù)據(jù)傳遞等。
后端部分指的是經(jīng)公網(wǎng)進(jìn)入了后端的服務(wù)器網(wǎng)絡(luò)里,包括了前置的負(fù)載均衡(Nginx 等)、應(yīng)用服務(wù)器、數(shù)據(jù)庫層等。秒殺活動(dòng)的整個(gè)流程可以用下圖來表示。

the-process-of-network-request
我們要去設(shè)計(jì)一個(gè)秒殺系統(tǒng),那自然也是從這兩大部分來進(jìn)行優(yōu)化。整體思路是盡量將流量擋在前面,讓盡量少的流量留到后端部分。因?yàn)樵酵蠖耍覀兊奶幚磉壿嬀驮街兀涮幚砟芰σ苍饺酢?/p>
前端優(yōu)化
對(duì)于前端部分來說,常見的優(yōu)化手段有:頁面靜態(tài)化 + CDN、請(qǐng)求頻率限制。
頁面靜態(tài)化 + CDN
一般來說,活動(dòng)頁面是流量最大的地方。活動(dòng)頁面上絕大部分內(nèi)容都是固定的,比如:商品描述、圖片等。這時(shí)候沒有必要每次都去請(qǐng)求服務(wù)端,而是將這些靜態(tài)的內(nèi)容放到 CDN 上。
每次打開頁面的時(shí)候,直接去請(qǐng)求 CDN 服務(wù)器,能極大地減少后端的請(qǐng)求流量。加入了 CDN 之后,其請(qǐng)求過程如下:

CDN 優(yōu)化靜態(tài)數(shù)據(jù)
所謂的 CDN 就是內(nèi)容分發(fā)網(wǎng)絡(luò),它由非常多臺(tái)分布在世界各地的緩存服務(wù)器組成。每次用戶請(qǐng)求特定域名的時(shí)候,會(huì)轉(zhuǎn)發(fā)到對(duì)應(yīng) CDN 的 DNS 解析服務(wù)器,隨后會(huì)返回一臺(tái)離用戶地理位置最近的一臺(tái) CDN 服務(wù)器。
隨后,用戶直接請(qǐng)求這臺(tái) CDN 服務(wù)器獲取數(shù)據(jù),從而極大地減少了長途網(wǎng)絡(luò)傳輸?shù)臅r(shí)間,并且也減少了后端服務(wù)器的壓力。
因此,對(duì)于秒殺活動(dòng)設(shè)計(jì)來說,我們可以將所有可以靜態(tài)化的內(nèi)容全部靜態(tài)化,然后將其配置在 CDN 服務(wù)器上。這樣既提高了用戶打開頁面的時(shí)間,又減少了后端服務(wù)器的壓力。
請(qǐng)求頻率限制
請(qǐng)求頻率限制,指的是根據(jù)業(yè)務(wù)的特點(diǎn),在前端做一些流量攔截,減少后端服務(wù)器的壓力。常見的攔截方式有:
- 設(shè)定一個(gè)請(qǐng)求概率,只允許 30% 的概率向后端發(fā)送接口請(qǐng)求。
- 設(shè)定一個(gè)請(qǐng)求頻率,例如 10 秒鐘只能請(qǐng)求 1 次,隨后按鈕置灰。
通過這種方式,我們可以減少很大一部分流量。但在具體實(shí)現(xiàn)的時(shí)候,可能需要考慮安全問題,預(yù)防某些用戶直接調(diào)用后臺(tái)接口,繞過前端的頻率檢查。
常見的方法是在頻率檢查時(shí)生成一個(gè)參數(shù),隨后請(qǐng)求后端服務(wù)時(shí)攜帶上該參數(shù)。沒有該參數(shù)的請(qǐng)求,都視為非法請(qǐng)求,直接拒絕該請(qǐng)求。
后端優(yōu)化
無論我們做多大的努力,始終還是會(huì)有不少流量會(huì)來到后端服務(wù)器這里。一般來說,后端的優(yōu)化有如下幾種方式:
- 增加緩存層 + 預(yù)熱數(shù)據(jù)
- MQ 異步處理
- 限流、熔斷、兜底
- 業(yè)務(wù)側(cè)優(yōu)化
- 增加緩存層 + 預(yù)熱數(shù)據(jù)
如果我們所有數(shù)據(jù)都去讀取數(shù)據(jù)庫,數(shù)據(jù)庫可能無法承受較大的流量,此時(shí)一個(gè)常見的優(yōu)化就是增加緩存層。
當(dāng)我們需要查詢數(shù)據(jù)庫之前,我們先去查詢緩存,這樣可以減少絕大部分的數(shù)據(jù)庫請(qǐng)求,減輕數(shù)據(jù)庫壓力。如果在緩存中找不到數(shù)據(jù),我們?cè)偃フ?qǐng)求數(shù)據(jù)庫,隨后再將數(shù)據(jù)緩存到緩存中。
在引入緩存層的時(shí)候,我們需要考慮緩存擊穿、緩存穿透的可能性,在寫相關(guān)代碼的時(shí)候就要做好這些優(yōu)化。另外,我們?cè)诿霘⒒顒?dòng)開始之前,可以手動(dòng)將熱點(diǎn)數(shù)據(jù)加載到緩存中,從而避免秒殺時(shí)去請(qǐng)求數(shù)據(jù)庫。
MQ 異步處理
我們知道秒殺活動(dòng)一般涉及搶購、下單、支付、發(fā)貨等階段,而搶購與后續(xù)的幾個(gè)階段是可以異步執(zhí)行的。為了避免對(duì)下單、支付、發(fā)貨等階段產(chǎn)生影響,我們可以將搶購階段與后續(xù)階段用 MQ 進(jìn)行解耦處理。當(dāng)用戶搶購成功后,往消息隊(duì)列中丟入一臺(tái)消息,隨后再由訂單系統(tǒng)消費(fèi)進(jìn)行下單處理。
通過各系統(tǒng)之間的解耦處理,我們可以將原本同步的處理方式變?yōu)楫惒教幚恚瑥亩蟠蟮臏p少了請(qǐng)求的處理時(shí)間,提高了系統(tǒng)的并發(fā)處理能力。其次,也能避免系統(tǒng)之間相互影響,提高了整體系統(tǒng)的穩(wěn)定性。
限流、熔斷、降級(jí)
雖然我們做了非常多的優(yōu)化措施,但還是可能存在請(qǐng)求超量的可能性,那怎么辦呢?
我們可以在每個(gè)業(yè)務(wù)系統(tǒng)做限流操作,從而避免因?yàn)檎?qǐng)求太多,導(dǎo)致整個(gè)系統(tǒng)都無法工作。當(dāng)并發(fā)請(qǐng)求在正常范圍內(nèi)時(shí),我們正常處理請(qǐng)求。當(dāng)超過設(shè)置的限流閾值時(shí),我們則直接拒絕該請(qǐng)求,提示用戶搶購失敗。
如果沒有限流操作,那么系統(tǒng)直接崩潰了,一個(gè)請(qǐng)求都處理不了。而通過限流這種方式,系統(tǒng)至少還可以保持正常工作,而不至于一個(gè)請(qǐng)求都處理不了。而超量的需求,本來就處理不了,因此提示失敗也是情理之中。
除了限流之外,不同的系統(tǒng)還可以采用熔斷、降級(jí)的服務(wù)治理措施。
熔斷指的是請(qǐng)求的錯(cuò)誤次數(shù)超過閾值時(shí),不再到用后端服務(wù),直接返回失敗。同時(shí)每隔一定時(shí)間放幾個(gè)請(qǐng)求去重試后端服務(wù),看看是否正常。如果正常則關(guān)閉熔斷狀態(tài),如果失敗則繼續(xù)快速失敗。熔斷的目的是避免因下游短暫的異常,導(dǎo)致上游不斷重試,最終造成下游有太多請(qǐng)求,最終壓垮下游系統(tǒng)。
降級(jí)指的是當(dāng)服務(wù)失敗或異常后,返回指定的默認(rèn)信息。降級(jí)的目的是保證有基本的信息,當(dāng)下游異常時(shí),與其返回空信息,不如返回一個(gè)有業(yè)務(wù)含義的默認(rèn)信息,可以提高用戶體驗(yàn)。
業(yè)務(wù)側(cè)優(yōu)化
一般來說,經(jīng)過上述的整體優(yōu)化之后,系統(tǒng)已經(jīng)能夠比較穩(wěn)當(dāng)?shù)貞?yīng)對(duì)秒殺活動(dòng)了。如果此時(shí)還是流量比較大,那么或許應(yīng)該從業(yè)務(wù)側(cè)去進(jìn)行優(yōu)化了。
例如 12306 剛開始的時(shí)候,購買時(shí)間都在同一時(shí)刻,這導(dǎo)致同一時(shí)刻并發(fā)量太大,系統(tǒng)經(jīng)常支撐不住。后來 12306 將購票周期放長,可以提前 20 天購買火車票。通過業(yè)務(wù)側(cè)的優(yōu)化,我們將本來在 1 個(gè)小時(shí)的搶購分?jǐn)偟搅?20 天,服務(wù)器壓力一下子降低了 480 倍!
張小龍也說過:如果公司最厲害的程序員來實(shí)現(xiàn)業(yè)務(wù)都覺得復(fù)雜,那很可能就是業(yè)務(wù)確實(shí)不合理,這時(shí)候應(yīng)該從業(yè)務(wù)側(cè)進(jìn)行優(yōu)化。
例如一個(gè)存儲(chǔ)了 10 億條記錄的消息記錄表,業(yè)務(wù)側(cè)既想查詢速度快,又想進(jìn)行 1 年數(shù)據(jù)范圍的數(shù)據(jù)查詢,這無論如何都是無法實(shí)現(xiàn)的。這時(shí)候就需要從業(yè)務(wù)需求側(cè)進(jìn)行優(yōu)化,否則是無法兩全其美的。
對(duì)于這個(gè)場(chǎng)景,一個(gè)合理的實(shí)現(xiàn)方式是:要實(shí)現(xiàn) 1 年數(shù)據(jù)范圍的查詢,那么只能根據(jù)消息 ID 進(jìn)行,因?yàn)檫@樣可以使用上索引。而要根據(jù)時(shí)間范圍進(jìn)行查詢,只能縮短查詢時(shí)間到 3 天內(nèi),這樣也可以滿足業(yè)務(wù)需求。
因此從業(yè)務(wù)側(cè)進(jìn)行優(yōu)化,是一個(gè)四兩撥千斤的辦法,可以極大地降低技術(shù)側(cè)實(shí)現(xiàn)的難度。
總結(jié)
設(shè)計(jì)一個(gè)秒殺系統(tǒng),整體而言可以從前端與后端進(jìn)行優(yōu)化。
對(duì)于前端優(yōu)化而言,可以從「頁面靜態(tài)化 + CDN」、請(qǐng)求頻率限制進(jìn)行優(yōu)化。
其中「頁面靜態(tài)化 + CDN」指的是將不變的靜態(tài)數(shù)據(jù)固定下來,然后放入 CDN 服務(wù)器,從而降低用戶請(qǐng)求的響應(yīng)速度,降低服務(wù)器的并發(fā)壓力。請(qǐng)求頻率限制,則是通過搶購概率與搶購頻率限制,降低后端服務(wù)器的服務(wù)壓力。
對(duì)于后端優(yōu)化而言,一般有「增加緩存層 + 預(yù)熱數(shù)據(jù)」、「MQ 異步處理」、「限流、熔斷、降級(jí)」、業(yè)務(wù)側(cè)優(yōu)化這 4 種優(yōu)化方式。
其中「增加緩存層 + 預(yù)熱數(shù)據(jù)」指的是將熱點(diǎn)數(shù)據(jù)存入緩存,并在活動(dòng)開始前提前加載到緩存中,降低數(shù)據(jù)庫層的讀取壓力。「MQ 異步處理」指的是對(duì)于非必要的業(yè)務(wù)邏輯,通過 MQ 進(jìn)行異步處理,降低請(qǐng)求處理延時(shí),同時(shí)提高業(yè)務(wù)系統(tǒng)整體穩(wěn)定性。
「限流、熔斷、降級(jí)」是對(duì)于整體微服務(wù)的保護(hù),其中限流指的是對(duì)請(qǐng)求進(jìn)行限制,當(dāng)超過限流閾值時(shí),直接拒絕請(qǐng)求,保護(hù)系統(tǒng)本身;熔斷指的是保護(hù)下游系統(tǒng),當(dāng)請(qǐng)求下游系統(tǒng)連續(xù)錯(cuò)誤超過閾值時(shí),自動(dòng)不去請(qǐng)求下游系統(tǒng),避免因重試流量過大擊垮下游系統(tǒng)。
降級(jí)指的是當(dāng)請(qǐng)求失敗時(shí),自動(dòng)返回默認(rèn)數(shù)據(jù),提高用戶體驗(yàn)。業(yè)務(wù)側(cè)優(yōu)化,則是指從業(yè)務(wù)層面去進(jìn)行邏輯優(yōu)化,從而降低技術(shù)復(fù)雜度,使得業(yè)務(wù)與技術(shù)復(fù)雜度達(dá)到一個(gè)平衡的狀態(tài),有利于更好地實(shí)現(xiàn)秒殺系統(tǒng)的高可用與高并發(fā)。
上面說到的 6 個(gè)優(yōu)化思路,是設(shè)計(jì)秒殺系統(tǒng)常見的優(yōu)化思路。但在實(shí)際業(yè)務(wù)場(chǎng)景中,除了要保障正常的功能設(shè)計(jì)之外,還還考慮防刷、安全、黑產(chǎn)等問題,此時(shí)可能需要多考慮一些其他優(yōu)化,例如:黃牛利用搶購工具搶購,導(dǎo)致正常用戶無法搶到商品等。
這時(shí)候可能需要考慮增加驗(yàn)證碼,用 App 設(shè)備指紋等風(fēng)控措施。此外,對(duì)于秒殺系統(tǒng)而言,做好業(yè)務(wù)指標(biāo)和系統(tǒng)指標(biāo)的埋點(diǎn)監(jiān)控也是非常重要的。

文章思維導(dǎo)圖
參考資料
- VIP!極客時(shí)間!系統(tǒng)學(xué)習(xí)!如何設(shè)計(jì)一個(gè)秒殺系統(tǒng)
- 秒殺系統(tǒng)設(shè)計(jì) - 掘金
- 秒殺系統(tǒng)怎么搞?虐死人......
- 架構(gòu)之高并發(fā):降級(jí)和熔斷 | Java 全棧知識(shí)體系
- 小米搶購限流峰值系統(tǒng)「大秒」架構(gòu)解密 - 一天不進(jìn)步,就是退步 - 博客園































