自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如果讓你設(shè)計(jì)一個(gè)秒殺系統(tǒng),你會(huì)怎么做?

開(kāi)發(fā) 架構(gòu)
秒殺本來(lái)就是一個(gè)看運(yùn)氣的事,誰(shuí)秒到算誰(shuí)的,沒(méi)秒到就算失敗,產(chǎn)品數(shù)量往往有限,秒到的必然是少數(shù)人,所以在請(qǐng)求從客戶端到達(dá)服務(wù)端并處理的過(guò)程中,可以對(duì)流量進(jìn)行層層過(guò)濾。

這個(gè)算是一個(gè)經(jīng)典面試題了,雖說(shuō)是一個(gè)場(chǎng)景題,但是也算是老八股了。

今天就從系統(tǒng)設(shè)計(jì)的角度來(lái)和小伙伴們聊一聊這個(gè)話題。

一般來(lái)說(shuō)秒殺系統(tǒng)需要考慮到下面這樣一些問(wèn)題:

  1. 瞬時(shí)高并發(fā)流量
  2. 熱點(diǎn)商品數(shù)據(jù)
  3. 庫(kù)存管理
  4. 重復(fù)下單
  5. 黃牛

接下來(lái)我們就這里提到的點(diǎn)逐一進(jìn)行分析。

一 瞬時(shí)高并發(fā)流量

應(yīng)對(duì)瞬時(shí)高并發(fā)流量,不是某一種方案就可以,是一個(gè)組合拳。另外大家要記得,系統(tǒng)設(shè)計(jì)沒(méi)有銀彈。

1.1 動(dòng)靜分離部署

這算是一個(gè)基本要求了,引入 Nginx,將靜態(tài)資源和動(dòng)態(tài)資源利用 Nginx 分流,靜態(tài)資源直接返回,動(dòng)態(tài)資源則轉(zhuǎn)發(fā)給后端服務(wù)器去處理。

圖片圖片

這一點(diǎn)其實(shí)還蠻重要,松哥之前就有遇到這個(gè)問(wèn)題,一開(kāi)始沒(méi)有動(dòng)靜分離部署,后來(lái)動(dòng)靜分離部署之后,系統(tǒng)并發(fā)能力提升 2 倍以上

不過(guò)如果愿意花點(diǎn)錢,把靜態(tài)資源都交給云服務(wù)商的 CDN 來(lái)處理,那就更好了。

一般來(lái)說(shuō)使用 CDN 是比較劃算的,因?yàn)?CDN 流量費(fèi)往往比云主機(jī)的流量費(fèi)便宜。

1.2 數(shù)據(jù)庫(kù)獨(dú)立部署

這個(gè)也算是基操了,將應(yīng)用程序和數(shù)據(jù)庫(kù)部署到一起,往往無(wú)法讓數(shù)據(jù)庫(kù)發(fā)揮自己的極限性能。正常來(lái)說(shuō),一臺(tái) 1C2G 的服務(wù)器上只部署 MySQL,就能做到每秒處理 200 次查詢請(qǐng)求,這樣的數(shù)據(jù)基本上就能滿足一個(gè)每天 100W PV 的小網(wǎng)站了。

但是你想想,1C2G 的服務(wù)器部署 MySQL 和應(yīng)用程序的話,估計(jì)卡的沒(méi)法用了。

將 MySQL 和應(yīng)用程序部署到一臺(tái)服務(wù)器上,往往會(huì)因?yàn)閮烧呋ハ嘤绊懚档驼w的并發(fā)性能,具體來(lái)說(shuō)可能會(huì)發(fā)生這些問(wèn)題:

  1. 高并發(fā)導(dǎo)致 CPU 被耗盡,進(jìn)而 MySQL 響應(yīng)變慢。
  2. 應(yīng)用程序處理請(qǐng)求的時(shí)候需要等待更長(zhǎng)的時(shí)間獲取數(shù)據(jù)庫(kù)的數(shù)據(jù),這個(gè)過(guò)程占用了大量的內(nèi)存。
  3. 系統(tǒng)內(nèi)存緊張導(dǎo)致 MySQL 中緩存的數(shù)據(jù)被回收,進(jìn)而拖慢 MySQL。
  4. 如此循環(huán)往復(fù),系統(tǒng)最終越來(lái)越慢甚至崩潰。

因此我們要做的第二件事情就是將數(shù)據(jù)庫(kù)和應(yīng)用程序獨(dú)立分開(kāi)部署。

1.3 流量過(guò)濾

秒殺本來(lái)就是一個(gè)看運(yùn)氣的事,誰(shuí)秒到算誰(shuí)的,沒(méi)秒到就算失敗,產(chǎn)品數(shù)量往往有限,秒到的必然是少數(shù)人,所以在請(qǐng)求從客戶端到達(dá)服務(wù)端并處理的過(guò)程中,可以對(duì)流量進(jìn)行層層過(guò)濾。

一般來(lái)說(shuō),請(qǐng)求主要經(jīng)過(guò)如下節(jié)點(diǎn):

圖片

由于秒殺的隨機(jī)性,我們可以這么做:

  1. Client 處也就是用戶請(qǐng)求發(fā)起的地方,我們就可以隨機(jī)丟棄一些請(qǐng)求,直接彈出秒殺失敗、網(wǎng)絡(luò)阻塞等等。
  2. 當(dāng)請(qǐng)求到達(dá) Nginx 之后,可以在 Nginx 處進(jìn)行限流,利用像 limit_req_zone、limit_req_conn 等模塊來(lái)實(shí)現(xiàn)不同的限流策略。
  3. 當(dāng)請(qǐng)求從 Nginx 上轉(zhuǎn)發(fā)到 Java 服務(wù)上之后,我們可以繼續(xù)使用一些限流工具,比如 Sentinel,或者自己利用 Redis 寫限流工具也可以,在這里繼續(xù)進(jìn)行限流。
  4. 當(dāng)請(qǐng)求突破層層關(guān)卡到達(dá)業(yè)務(wù)層之后,對(duì)于實(shí)時(shí)性要求不高的數(shù)據(jù),直接從緩存查詢,緩存優(yōu)先查本地緩存,其次是遠(yuǎn)程分布式緩存如 Redis,緩存中沒(méi)有數(shù)據(jù)的話,最后再是 MySQL。

1.4 頁(yè)面靜態(tài)化

對(duì)于熱點(diǎn)數(shù)據(jù)頁(yè)面可以進(jìn)行靜態(tài)化處理。

比如秒殺商品頁(yè)、秒殺商品詳情頁(yè)等等這些熱點(diǎn)頁(yè)面直接自動(dòng)進(jìn)行靜態(tài)化處理,這樣用戶每次訪問(wèn)的時(shí)候,直接返回現(xiàn)成的頁(yè)面,就不用走數(shù)據(jù)庫(kù)了。

如果頁(yè)面數(shù)據(jù)發(fā)生變化,重新自動(dòng)生成靜態(tài)頁(yè)面即可。

二 熱點(diǎn)商品數(shù)據(jù)

接下來(lái)就是熱點(diǎn)商品數(shù)據(jù)的處理了。

秒殺這種事情,在秒殺活動(dòng)開(kāi)始之前,我們基本上就能夠確定哪些數(shù)據(jù)是熱點(diǎn)數(shù)據(jù)了,所以處理處理起來(lái)相對(duì)來(lái)說(shuō)并不難。

不過(guò)需要注意的是,能緩存的數(shù)據(jù)肯定是一些商品信息類的數(shù)據(jù),對(duì)于像庫(kù)存這類實(shí)時(shí)性要求極高的數(shù)據(jù),是不適合緩存的。

2.1 緩存預(yù)熱

緩存預(yù)熱主要從兩方面入手:

  1. 本地緩存預(yù)熱
  2. Redis 緩存預(yù)熱

查詢的時(shí)候先查本地緩存,沒(méi)有再查 Redis 緩存,這樣能夠有效避免 Redis 的熱 Key 問(wèn)題。

2.2 數(shù)據(jù)拆分

另一方面就是我們要避免熱點(diǎn)數(shù)據(jù)聚集到一起,將熱點(diǎn)數(shù)據(jù)進(jìn)行拆分。避免從一個(gè)緩存處去獲取多個(gè)熱點(diǎn)數(shù)據(jù),這樣就能降低緩存的壓力。

比如:

  • 商品詳情數(shù)據(jù)
  • 價(jià)格數(shù)據(jù)
  • 秒殺規(guī)則數(shù)據(jù)
  • 。。。

可以對(duì)這些熱點(diǎn)數(shù)據(jù)進(jìn)行拆分,其實(shí)拆分之后,熱點(diǎn)數(shù)據(jù)也就不那么“熱”了。

三 庫(kù)存管理

庫(kù)存因?yàn)閷?shí)時(shí)性要求比較高,因此就不方便用緩存。

庫(kù)存管理要是做不好,可能會(huì)發(fā)生超賣或者少賣。

那么庫(kù)存管理怎么做呢?保險(xiǎn)的方案當(dāng)然就是直接去數(shù)據(jù)庫(kù)扣減,但是數(shù)據(jù)庫(kù)并發(fā)能力有限,所以往往還需要結(jié)合緩存來(lái)做。

我們分別來(lái)看。

3.1 數(shù)據(jù)庫(kù)扣減

數(shù)據(jù)庫(kù)扣減,為了避免把庫(kù)存扣成負(fù)數(shù),一般來(lái)說(shuō)我們有兩種思路:

  1. 悲觀鎖
  2. 樂(lè)觀鎖

在高并發(fā)場(chǎng)景下,悲觀鎖會(huì)導(dǎo)致更新效率降低很多;而樂(lè)觀鎖則會(huì)導(dǎo)致大量的失敗。似乎都不是一個(gè)很好的選擇。

其實(shí)我們只是要保證庫(kù)存不被減為負(fù)數(shù)而已,那么其實(shí)就可以在更新 SQL 中添加一個(gè)條件就行了,像下面這樣:

***** and 庫(kù)存>=0

大致上這樣就可以了。

不過(guò)只是這樣做還不夠,因?yàn)閿?shù)據(jù)庫(kù)的并發(fā)能力在哪擺著呢。所以我們還是要利用緩存。

3.2 緩存扣減

由于 Redis 本身就是單線程執(zhí)行的,因此我們?cè)俳Y(jié)合上 Lua 腳本,就可以保證扣減庫(kù)存這個(gè)操作的原子性。

在 Lua 腳本中我們可以獲取到庫(kù)存數(shù)據(jù),然后判斷庫(kù)存,沒(méi)問(wèn)題再進(jìn)行扣減。

Redis 本身的高性能+單線程執(zhí)行+Lua 腳本的原子性,這三點(diǎn)結(jié)合起來(lái)就可以確保上述操作是沒(méi)有問(wèn)題的。

3.3 最佳實(shí)踐

在具體實(shí)踐中,往往是 3.1 和 3.2 結(jié)合起來(lái)。

具體流程是這樣:

首先 Redis 做扣減,扣減完了之后,發(fā)送一條消息給 MQ,應(yīng)用程序再去消費(fèi)這條消息,消費(fèi)消息時(shí)完成數(shù)據(jù)庫(kù)的扣減。

這個(gè)過(guò)程中我們需要確保好 MQ 消息的可靠性和冪等性,處理好消息積壓。

當(dāng)然,穩(wěn)妥起見(jiàn)還需要有對(duì)賬機(jī)制,定時(shí)拉取 Redis 中的數(shù)據(jù)和數(shù)據(jù)庫(kù)中的數(shù)據(jù)進(jìn)行對(duì)比,保證數(shù)據(jù)的一致性。

四 重復(fù)下單

秒殺場(chǎng)景下用戶由于比較焦急,頻繁點(diǎn)擊可能造成重復(fù)下單,因此我們需要處理好下單操作的冪等性。

這個(gè)也有很多思路,需要多管齊下。

4.1 前端置灰

前端用戶點(diǎn)擊之后,就對(duì)秒殺按鈕進(jìn)行置灰操作,同時(shí)提醒用戶目前正在進(jìn)行秒殺。

這是基操,但是不能從根本上解決問(wèn)題,還得配合后段冪等性處理。

4.2 后端冪等性處理

后段冪等性處理有很多方案,可以利用 Token 機(jī)制,這個(gè)松哥之前也有很多文章介紹,不多說(shuō)。

同時(shí)因?yàn)槊霘⑦@種場(chǎng)景往往是限購(gòu)的,因此在用戶下單的時(shí)候可以判斷是否有在途訂單或者用戶是否已經(jīng)下單,進(jìn)而決定當(dāng)前下單操作是否能夠成功。

五 黃牛

薅羊毛的黃牛也是我們要考慮的一個(gè)問(wèn)題。

5.1 識(shí)別黃牛

首先我們要識(shí)別出來(lái)哪些用戶可能是黃牛,一般來(lái)說(shuō),我們可以通過(guò)如下方式來(lái)識(shí)別:

  1. 請(qǐng)求頻率:監(jiān)測(cè)用戶的請(qǐng)求頻率,若某一賬戶的請(qǐng)求過(guò)于頻繁,則可能是黃牛使用自動(dòng)化工具發(fā)出的。
  2. 訪問(wèn)模式:分析用戶的訪問(wèn)模式,例如短時(shí)間內(nèi)大量的重復(fù)請(qǐng)求或者非正常人類行為的訪問(wèn)模式。
  3. IP 地址:檢查請(qǐng)求來(lái)源的 IP 地址,對(duì)于同一 IP 地址下頻繁的請(qǐng)求進(jìn)行限制或標(biāo)記。

如果公司有足夠的人力資源,這塊可以建立預(yù)測(cè)模型,通過(guò)模型去分析哪些人可能是黃牛。

5.2 防止黃牛

當(dāng)我們識(shí)別出來(lái)黃牛之后,一般來(lái)說(shuō)有如下一些辦法:

  • 圖形驗(yàn)證碼(CAPTCHA):在關(guān)鍵環(huán)節(jié)加入圖形驗(yàn)證碼,要求用戶識(shí)別并輸入相應(yīng)的字符,以防止自動(dòng)化工具的使用。
  • 滑動(dòng)驗(yàn)證:在關(guān)鍵環(huán)節(jié)采用滑動(dòng)驗(yàn)證等交互式驗(yàn)證方式,這類驗(yàn)證方式難以被自動(dòng)化工具模擬,這也是大家目前見(jiàn)到的最多的驗(yàn)證方式了。
  • 行為驗(yàn)證:基于用戶的行為軌跡(如鼠標(biāo)移動(dòng)軌跡、鍵盤輸入模式等)來(lái)進(jìn)行驗(yàn)證,這個(gè)目前松哥只在京東圖書(shū)上見(jiàn)過(guò)這種驗(yàn)證方式。
  • 請(qǐng)求頻率限制:對(duì)識(shí)別出來(lái)的用戶或 IP 地址的請(qǐng)求頻率進(jìn)行限制,超出限制則暫時(shí)禁止訪問(wèn),這塊利用 Nginx 或者 Sentinel 就能實(shí)現(xiàn)。
  • 黑名單:對(duì)于已知的黃牛 IP 地址或賬戶進(jìn)行封禁處理,這塊可以直接在 Nginx 上處理,也可以在網(wǎng)關(guān)如 Spring Cloud Gateway 上處理。
  • 動(dòng)態(tài)調(diào)整:根據(jù)系統(tǒng)的實(shí)時(shí)負(fù)載情況動(dòng)態(tài)調(diào)整限流閾值。

六 小結(jié)

秒殺是一個(gè)大工程,以上是松哥和大家分享的一些實(shí)現(xiàn)思路,具體落實(shí)下來(lái)還有很多細(xì)節(jié)需要處理。

借助本文希望小伙伴們?cè)诿嬖嚨臅r(shí)候不怯場(chǎng),能夠回答出來(lái)。

責(zé)任編輯:武曉燕 來(lái)源: 江南一點(diǎn)雨
相關(guān)推薦

2021-01-14 05:23:32

高并發(fā)消息中間件

2022-09-19 18:14:58

分布式架構(gòu)中間件

2022-02-17 08:57:18

內(nèi)存設(shè)計(jì)進(jìn)程

2023-08-28 08:52:49

監(jiān)聽(tīng)頁(yè)面用戶

2024-06-21 08:15:25

2023-09-02 21:22:36

Airbnb系統(tǒng)

2023-01-15 17:57:12

緩存技術(shù)kafka磁盤

2021-05-13 07:32:17

培訓(xùn)代碼同事

2025-04-25 07:15:00

勒索軟件企業(yè)安全

2019-11-27 15:19:44

系統(tǒng)緩存架構(gòu)

2020-08-03 08:30:00

JSCSS排序

2023-12-22 09:03:31

2023-12-29 11:32:27

2023-12-14 17:27:28

架構(gòu)設(shè)計(jì)數(shù)據(jù)表

2025-03-17 02:00:00

2023-11-08 07:05:07

架構(gòu)設(shè)計(jì)群聊系統(tǒng)

2025-04-29 02:00:00

高并發(fā)系統(tǒng)場(chǎng)景

2024-03-19 00:52:52

前端網(wǎng)頁(yè)篡改

2020-03-03 07:59:29

設(shè)計(jì)秒殺系統(tǒng)

2025-02-11 09:51:52

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)