阻塞隊(duì)列怎么么實(shí)現(xiàn)?超賣問題?整體怎么實(shí)現(xiàn)?
5 設(shè)計(jì)一個(gè)秒殺系統(tǒng)
特點(diǎn):高并發(fā),請(qǐng)求量遠(yuǎn)大于庫存量,只有少數(shù)能成功;邏輯比較簡單,下單減庫存;
設(shè)計(jì)理念:**限流,**只有少部分流量能進(jìn)入后端;削峰,將瞬間的高流量轉(zhuǎn)換成平穩(wěn)的流量(比如異步處理)。內(nèi)存緩存:秒殺系統(tǒng)最大的瓶頸一般都是數(shù)據(jù)庫讀寫,由于數(shù)據(jù)庫讀寫屬于磁盤IO,性能很低,如果能夠把部分?jǐn)?shù)據(jù)或業(yè)務(wù)邏輯轉(zhuǎn)移到內(nèi)存緩存,效率會(huì)有極大地提升。分布式處理。
流程:前端秒殺界面-服務(wù)端控制器(網(wǎng)關(guān))-服務(wù)層-數(shù)據(jù)庫層
前端瀏覽器可做的:將頁面能靜態(tài)的元素都用靜態(tài)(靜態(tài)不涉及服務(wù)端),通過CDN對(duì)抗峰值;禁止重復(fù)提交:用戶提交之后按鈕置灰,禁止重復(fù)提交;用戶限流:在某一時(shí)間段內(nèi)只允許用戶提交一次請(qǐng)求,比如可以采取IP限流。
服務(wù)端控制器層(網(wǎng)關(guān)層)
限制uid(UserID)訪問頻率:我們上面攔截了瀏覽器訪問的請(qǐng)求,但針對(duì)某些惡意攻擊或其它插件,在服務(wù)端控制層需要針對(duì)同一個(gè)訪問uid,限制訪問頻率。
服務(wù)層
1、采用消息隊(duì)列緩存請(qǐng)求:既然服務(wù)層知道庫存只有100臺(tái)手機(jī),那完全沒有必要把100W個(gè)請(qǐng)求都傳遞到數(shù)據(jù)庫啊,那么可以先把這些請(qǐng)求都寫到消息隊(duì)列緩存一下,數(shù)據(jù)庫層訂閱消息減庫存,減庫存成功的請(qǐng)求返回秒殺成功,失敗的返回秒殺結(jié)束。
2、利用緩存應(yīng)對(duì)讀請(qǐng)求:對(duì)類似于12306等購票業(yè)務(wù),是典型的讀多寫少業(yè)務(wù),大部分請(qǐng)求是查詢請(qǐng)求,所以可以利用緩存分擔(dān)數(shù)據(jù)庫壓力。
3、**利用緩存應(yīng)對(duì)寫請(qǐng)求:**緩存也是可以應(yīng)對(duì)寫請(qǐng)求的,比如我們就可以把數(shù)據(jù)庫中的庫存數(shù)據(jù)轉(zhuǎn)移到Redis緩存中,所有減庫存操作都在Redis中進(jìn)行,然后再通過后臺(tái)進(jìn)程把Redis中的用戶秒殺請(qǐng)求同步到數(shù)據(jù)庫中。(redis就是非關(guān)系數(shù)據(jù)庫,可以在內(nèi)存處理數(shù)據(jù),讀寫比較快)
秒殺系統(tǒng)特點(diǎn)是并發(fā)量極大,但實(shí)際秒殺成功的請(qǐng)求數(shù)量卻很少,所以如果不在前端攔截很可能造成數(shù)據(jù)庫讀寫鎖沖突,甚至導(dǎo)致死鎖,最終請(qǐng)求超時(shí)。
總結(jié):秒殺系統(tǒng)特點(diǎn)是瞬間高并發(fā)峰值。
第一就是前端限流。
比如按鈕只能點(diǎn)一次,IP限流;
比如靜態(tài)頁面,用戶瀏覽商品等常規(guī)操作,并不會(huì)請(qǐng)求到服務(wù)端。只有到了秒殺時(shí)間點(diǎn),并且用戶主動(dòng)點(diǎn)了秒殺按鈕才允許訪問服務(wù)端。
比如使用CDN,使用戶就近獲取所需內(nèi)容,降低網(wǎng)絡(luò)擁塞,提高用戶訪問響應(yīng)速度和命中率。
比如提高參加的門檻,會(huì)員才能參加;比如分批搶,這些都是產(chǎn)品經(jīng)理的問題了,不算技術(shù)問題。
第二點(diǎn):由于只有少部分商品,所以大部分用戶都是返回失敗,下單成功才會(huì)寫庫存。是典型的讀多寫少的場景,該用緩存了。
針對(duì)讀多寫少場景,大量讀請(qǐng)求可能會(huì)擊沉數(shù)據(jù)庫,所以可以用緩存比如redis。可能會(huì)遇到緩存擊穿(熱點(diǎn)數(shù)據(jù)永不過期,加鎖),穿透(接口校驗(yàn),布隆過濾器,返回固定值并寫緩存),雪崩(過期時(shí)間打散)等問題要注意解決。更多的話可以用redis集群,以及涉及集群的一些問題。
第三點(diǎn)就是針對(duì)庫存問題。
比如真正的秒殺商品的場景,不是說扣完庫存,就完事了,如果用戶在一段時(shí)間內(nèi),還沒完成支付,扣減的庫存是要加回去的。所以,在這里引出了一個(gè)預(yù)扣庫存的概念
以及庫存超賣問題?我們?cè)跍p庫存一般先檢查庫存量是否大于0,是的話就執(zhí)行減庫存,但是這兩個(gè)操作不是原子操作,所以很有可能檢查大于0,但是在減庫存之前被別的用戶買完了。
解決方法可以是加互斥鎖,這樣就不會(huì)出現(xiàn)多個(gè)線程訪問同一個(gè)共享變量的情況。但是性能太低了。
**樂觀鎖:用CAS,版本號(hào)解決,適用于讀多寫少的場景。**效率高一點(diǎn)。
真正并發(fā)量大的是秒殺功能,下單和支付功能實(shí)際并發(fā)量很小。所以,我們?cè)谠O(shè)計(jì)秒殺系統(tǒng)時(shí),有必要把下單和支付功能從秒殺的主流程中拆分出來,特別是下單功能要做成mq異步處理的。
如果使用mq,需要關(guān)注以下幾個(gè)問題:
消息丟失問題:原因有很多,比如:網(wǎng)絡(luò)問題、broker掛了、mq服務(wù)端磁盤問題等(解決思路,消費(fèi)前,先寫入消息表,轉(zhuǎn)態(tài)為待處理,只有成功消費(fèi),回調(diào)函數(shù)修改狀態(tài)為已處理,每隔一段時(shí)間檢查消息表,待處理就重試)
重復(fù)消費(fèi):本來消費(fèi)者消費(fèi)消息時(shí),在ack應(yīng)答的時(shí)候,如果網(wǎng)絡(luò)超時(shí),本身就可能會(huì)消費(fèi)重復(fù)的消息。但由于消息發(fā)送者增加了重試機(jī)制,會(huì)導(dǎo)致消費(fèi)者重復(fù)消息的概率增大。那么,如何解決重復(fù)消息問題呢?(加一張消息處理表,先判斷表里有沒有,有就直接返回,沒有就下單并且加入到處理表,要保證原子操作)
(總結(jié):前端限流(按鈕,ip,CDN) 讀多寫少加緩存(緩存相關(guān)問題),庫存超賣問題解決(樂觀鎖悲觀鎖),消息隊(duì)列異步處理下單支付操作(削峰)消費(fèi)丟失重復(fù)問題)
消息隊(duì)列有哪些實(shí)現(xiàn)形式?
消息隊(duì)列的作用:解耦,異步,削峰。
解耦就是生產(chǎn)者和很多消費(fèi)者解耦,A只需要把消息寫到隊(duì)列中,不關(guān)心誰用,消費(fèi)者掛了或者超時(shí)都跟A無關(guān)。
異步削峰:比如A是主要壓力業(yè)務(wù)也就是秒殺,而下單支付都是次要業(yè)務(wù),如果一次要搞完就會(huì)讓主要業(yè)務(wù)延遲太久,鎖爭用太多,崩潰,隊(duì)列先暫存秒殺成功,其他的次要任務(wù)不急著實(shí)現(xiàn)。文章來源:http://www.zghlxwxcb.cn/news/detail-428197.html
有成熟的rabitMQ,kafka等,以及有阻塞隊(duì)列,有界無界的,鏈表形式的等等。文章來源地址http://www.zghlxwxcb.cn/news/detail-428197.html
到了這里,關(guān)于關(guān)于秒殺系統(tǒng)的一系列問題的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!