掌握這些,高并發(fā)秒殺系統(tǒng)就不用擔(dān)心了!
很多小伙伴反饋說(shuō),高并發(fā)專(zhuān)題學(xué)了那么久,但是,在真正做項(xiàng)目時(shí),仍然不知道如何下手處理高并發(fā)業(yè)務(wù)場(chǎng)景!
圖片來(lái)自 Pexels
甚至很多小伙伴仍然停留在只是簡(jiǎn)單的提供接口(CRUD)階段,不知道學(xué)習(xí)的并發(fā)知識(shí)如何運(yùn)用到實(shí)際項(xiàng)目中,就更別提如何構(gòu)建高并發(fā)系統(tǒng)了!
究竟什么樣的系統(tǒng)算是高并發(fā)系統(tǒng)?今天,我們就一起解密高并發(fā)業(yè)務(wù)場(chǎng)景下典型的秒殺系統(tǒng)的架構(gòu),結(jié)合高并發(fā)專(zhuān)題下的其他文章,學(xué)以致用。
電商系統(tǒng)架構(gòu)
在電商領(lǐng)域,存在著典型的秒殺業(yè)務(wù)場(chǎng)景,那何謂秒殺場(chǎng)景呢。簡(jiǎn)單的來(lái)說(shuō)就是一件商品的購(gòu)買(mǎi)人數(shù)遠(yuǎn)遠(yuǎn)大于這件商品的庫(kù)存,而且這件商品在很短的時(shí)間內(nèi)就會(huì)被搶購(gòu)一空。
比如每年的 618、雙 11 大促,小米新品促銷(xiāo)等業(yè)務(wù)場(chǎng)景,就是典型的秒殺業(yè)務(wù)場(chǎng)景。
我們可以將電商系統(tǒng)的架構(gòu)簡(jiǎn)化成下圖所示:
由圖所示,我們可以簡(jiǎn)單的將電商系統(tǒng)的核心層分為:負(fù)載均衡層、應(yīng)用層和持久層。
接下來(lái),我們就預(yù)估下每一層的并發(fā)量:
- 假如負(fù)載均衡層使用的是高性能的 Nginx,則我們可以預(yù)估 Nginx 最大的并發(fā)度為:10W+,這里是以萬(wàn)為單位。
- 假設(shè)應(yīng)用層我們使用的是 Tomcat,而 Tomcat 的最大并發(fā)度可以預(yù)估為 800 左右,這里是以百為單位。
- 假設(shè)持久層的緩存使用的是 Redis,數(shù)據(jù)庫(kù)使用的是 MySQL,MySQL 的最大并發(fā)度可以預(yù)估為 1000 左右,以千為單位。Redis 的最大并發(fā)度可以預(yù)估為 5W 左右,以萬(wàn)為單位。
所以,負(fù)載均衡層、應(yīng)用層和持久層各自的并發(fā)度是不同的,那么,為了提升系統(tǒng)的總體并發(fā)度和緩存,我們通??梢圆扇∧男┓桨改?
①系統(tǒng)擴(kuò)容
系統(tǒng)擴(kuò)容包括垂直擴(kuò)容和水平擴(kuò)容,增加設(shè)備和機(jī)器配置,絕大多數(shù)的場(chǎng)景有效。
②緩存
本地緩存或者集中式緩存,減少網(wǎng)絡(luò) IO,基于內(nèi)存讀取數(shù)據(jù)。大部分場(chǎng)景有效。
③讀寫(xiě)分離
采用讀寫(xiě)分離,分而治之,增加機(jī)器的并行處理能力。
秒殺系統(tǒng)的特點(diǎn)
對(duì)于秒殺系統(tǒng)來(lái)說(shuō),我們可以從業(yè)務(wù)和技術(shù)兩個(gè)角度來(lái)闡述其自身存在的一些特點(diǎn)。
秒殺系統(tǒng)的業(yè)務(wù)特點(diǎn)
這里,我們可以使用 12306 網(wǎng)站來(lái)舉例,每年春運(yùn)時(shí),12306 網(wǎng)站的訪問(wèn)量是非常大的,但是網(wǎng)站平時(shí)的訪問(wèn)量卻是比較平緩的,也就是說(shuō),每年春運(yùn)時(shí)節(jié),12306 網(wǎng)站的訪問(wèn)量會(huì)出現(xiàn)瞬時(shí)突增的現(xiàn)象。
再比如,小米秒殺系統(tǒng),在上午 10 點(diǎn)開(kāi)售商品,10 點(diǎn)前的訪問(wèn)量比較平緩,10 點(diǎn)時(shí)同樣會(huì)出現(xiàn)并發(fā)量瞬時(shí)突增的現(xiàn)象。
所以,秒殺系統(tǒng)的流量和并發(fā)量我們可以使用下圖來(lái)表示:
由圖可以看出,秒殺系統(tǒng)的并發(fā)量存在瞬時(shí)凸峰的特點(diǎn),也叫做流量突刺現(xiàn)象。
我們可以將秒殺系統(tǒng)的特點(diǎn)總結(jié)如下:
①限時(shí)、限量、限價(jià)
在規(guī)定的時(shí)間內(nèi)進(jìn)行;秒殺活動(dòng)中商品的數(shù)量有限;商品的價(jià)格會(huì)遠(yuǎn)遠(yuǎn)低于原來(lái)的價(jià)格,也就是說(shuō),在秒殺活動(dòng)中,商品會(huì)以遠(yuǎn)遠(yuǎn)低于原來(lái)的價(jià)格出售。
例如,秒殺活動(dòng)的時(shí)間僅限于某天上午 10 點(diǎn)到 10 點(diǎn)半,商品數(shù)量只有 10 萬(wàn)件,售完為止,而且商品的價(jià)格非常低,例如:1 元購(gòu)等業(yè)務(wù)場(chǎng)景。
限時(shí)、限量和限價(jià)可以單獨(dú)存在,也可以組合存在。
②活動(dòng)預(yù)熱
需要提前配置活動(dòng);活動(dòng)還未開(kāi)始時(shí),用戶可以查看活動(dòng)的相關(guān)信息;秒殺活動(dòng)開(kāi)始前,對(duì)活動(dòng)進(jìn)行大力宣傳。
③持續(xù)時(shí)間短
購(gòu)買(mǎi)的人數(shù)數(shù)量龐大;商品會(huì)迅速售完。在系統(tǒng)流量呈現(xiàn)上,就會(huì)出現(xiàn)一個(gè)突刺現(xiàn)象,此時(shí)的并發(fā)訪問(wèn)量是非常高的,大部分秒殺場(chǎng)景下,商品會(huì)在極短的時(shí)間內(nèi)售完。
秒殺系統(tǒng)的技術(shù)特點(diǎn)
我們可以將秒殺系統(tǒng)的技術(shù)特點(diǎn)總結(jié)如下:
①瞬時(shí)并發(fā)量非常高
大量用戶會(huì)在同一時(shí)間搶購(gòu)商品;瞬間并發(fā)峰值非常高。
②讀多寫(xiě)少
系統(tǒng)中商品頁(yè)的訪問(wèn)量巨大;商品的可購(gòu)買(mǎi)數(shù)量非常少;庫(kù)存的查詢?cè)L問(wèn)數(shù)量遠(yuǎn)遠(yuǎn)大于商品的購(gòu)買(mǎi)數(shù)量。
在商品頁(yè)中往往會(huì)加入一些限流措施,例如早期的秒殺系統(tǒng)商品頁(yè)會(huì)加入驗(yàn)證碼來(lái)平滑前端對(duì)系統(tǒng)的訪問(wèn)流量,近期的秒殺系統(tǒng)商品詳情頁(yè)會(huì)在用戶打開(kāi)頁(yè)面時(shí),提示用戶登錄系統(tǒng)。這都是對(duì)系統(tǒng)的訪問(wèn)進(jìn)行限流的一些措施。
③流程簡(jiǎn)單
秒殺系統(tǒng)的業(yè)務(wù)流程一般比較簡(jiǎn)單;總體上來(lái)說(shuō),秒殺系統(tǒng)的業(yè)務(wù)流程可以概括為:下單減庫(kù)存。
針對(duì)這種短時(shí)間內(nèi)大流量的系統(tǒng)來(lái)說(shuō),就不太適合使用系統(tǒng)擴(kuò)容了,因?yàn)榧词瓜到y(tǒng)擴(kuò)容了,也就是在很短的時(shí)間內(nèi)會(huì)使用到擴(kuò)容后的系統(tǒng),大部分時(shí)間內(nèi),系統(tǒng)無(wú)需擴(kuò)容即可正常訪問(wèn)。
那么,我們可以采取哪些方案來(lái)提升系統(tǒng)的秒殺性能呢?
秒殺系統(tǒng)方案
針對(duì)秒殺系統(tǒng)的特點(diǎn),我們可以采取如下的措施來(lái)提升系統(tǒng)的性能。
①異步解耦
將整體流程進(jìn)行拆解,核心流程通過(guò)隊(duì)列方式進(jìn)行控制。
②限流防刷
控制網(wǎng)站整體流量,提高請(qǐng)求的門(mén)檻,避免系統(tǒng)資源耗盡。
③資源控制
將整體流程中的資源調(diào)度進(jìn)行控制,揚(yáng)長(zhǎng)避短。由于應(yīng)用層能夠承載的并發(fā)量比緩存的并發(fā)量少很多。
所以,在高并發(fā)系統(tǒng)中,我們可以直接使用 OpenResty 由負(fù)載均衡層訪問(wèn)緩存,避免了調(diào)用應(yīng)用層的性能損耗。
大家可以到 https://openresty.org/cn/ 來(lái)了解有關(guān) OpenResty 更多的知識(shí)。
同時(shí),由于秒殺系統(tǒng)中,商品數(shù)量比較少,我們也可以使用動(dòng)態(tài)渲染技術(shù),CDN 技術(shù)來(lái)加速網(wǎng)站的訪問(wèn)性能。
如果在秒殺活動(dòng)開(kāi)始時(shí),并發(fā)量太高時(shí),我們可以將用戶的請(qǐng)求放入隊(duì)列中進(jìn)行處理,并為用戶彈出排隊(duì)頁(yè)面。
秒殺系統(tǒng)時(shí)序圖
網(wǎng)上很多的秒殺系統(tǒng)和對(duì)秒殺系統(tǒng)的解決方案,并不是真正的秒殺系統(tǒng),他們采用的只是同步處理請(qǐng)求的方案,一旦并發(fā)量真的上來(lái)了,他們所謂的秒殺系統(tǒng)的性能會(huì)急劇下降。我們先來(lái)看一下秒殺系統(tǒng)在同步下單時(shí)的時(shí)序圖。
同步下單流程:
①用戶發(fā)起秒殺請(qǐng)求
在同步下單流程中,首先,用戶發(fā)起秒殺請(qǐng)求。商城服務(wù)需要依次執(zhí)行如下流程來(lái)處理秒殺請(qǐng)求的業(yè)務(wù)。
識(shí)別驗(yàn)證碼是否正確:商城服務(wù)判斷用戶發(fā)起秒殺請(qǐng)求時(shí)提交的驗(yàn)證碼是否正確。
判斷活動(dòng)是否已經(jīng)結(jié)束:驗(yàn)證當(dāng)前秒殺活動(dòng)是否已經(jīng)結(jié)束。
驗(yàn)證訪問(wèn)請(qǐng)求是否處于黑名單:在電商領(lǐng)域中,存在著很多的惡意競(jìng)爭(zhēng),也就是說(shuō),其他商家可能會(huì)通過(guò)不正當(dāng)手段來(lái)惡意請(qǐng)求秒殺系統(tǒng),占用系統(tǒng)大量的帶寬和其他系統(tǒng)資源。
此時(shí),就需要使用風(fēng)控系統(tǒng)等實(shí)現(xiàn)黑名單機(jī)制。為了簡(jiǎn)單,也可以使用攔截器統(tǒng)計(jì)訪問(wèn)頻次實(shí)現(xiàn)黑名單機(jī)制。
驗(yàn)證真實(shí)庫(kù)存是否足夠:系統(tǒng)需要驗(yàn)證商品的真實(shí)庫(kù)存是否足夠,是否能夠支持本次秒殺活動(dòng)的商品庫(kù)存量。
扣減緩存中的庫(kù)存:在秒殺業(yè)務(wù)中,往往會(huì)將商品庫(kù)存等信息存放在緩存中,此時(shí),還需要驗(yàn)證秒殺活動(dòng)使用的商品庫(kù)存是否足夠,并且需要扣減秒殺活動(dòng)的商品庫(kù)存數(shù)量。
計(jì)算秒殺的價(jià)格:由于在秒殺活動(dòng)中,商品的秒殺價(jià)格和商品的真實(shí)價(jià)格存在差異,所以,需要計(jì)算商品的秒殺價(jià)格。
注意:如果在秒殺場(chǎng)景中,系統(tǒng)涉及的業(yè)務(wù)更加復(fù)雜的話,會(huì)涉及更多的業(yè)務(wù)操作,這里,我只是列舉出一些常見(jiàn)的業(yè)務(wù)操作。
②提交訂單
訂單入口:將用戶提交的訂單信息保存到數(shù)據(jù)庫(kù)中。
扣減真實(shí)庫(kù)存:訂單入庫(kù)后,需要在商品的真實(shí)庫(kù)存中將本次成功下單的商品數(shù)量扣除。
如果我們使用上述流程開(kāi)發(fā)了一個(gè)秒殺系統(tǒng),當(dāng)用戶發(fā)起秒殺請(qǐng)求時(shí),由于系統(tǒng)每個(gè)業(yè)務(wù)流程都是串行執(zhí)行的,整體上系統(tǒng)的性能不會(huì)太高,當(dāng)并發(fā)量太高時(shí),我們會(huì)為用戶彈出下面的排隊(duì)頁(yè)面,來(lái)提示用戶進(jìn)行等待。
此時(shí)的排隊(duì)時(shí)間可能是 15 秒,也可能是 30 秒,甚至是更長(zhǎng)時(shí)間。這就存在一個(gè)問(wèn)題:在用戶發(fā)起秒殺請(qǐng)求到服務(wù)器返回結(jié)果的這段時(shí)間內(nèi),客戶端和服務(wù)器之間的連接不會(huì)被釋放,這就會(huì)占大量占用服務(wù)器的資源。
網(wǎng)上很多介紹如何實(shí)現(xiàn)秒殺系統(tǒng)的文章都是采用的這種方式,那么,這種方式能做秒殺系統(tǒng)嗎?
答案是可以做,但是這種方式支撐的并發(fā)量并不是太高。此時(shí),有些網(wǎng)友可能會(huì)問(wèn):我們公司就是這樣做的秒殺系統(tǒng)啊!上線后一直在用,沒(méi)啥問(wèn)題啊!
我想說(shuō)的是:使用同步下單方式確實(shí)可以做秒殺系統(tǒng),但是同步下單的性能不會(huì)太高。
之所以你們公司采用同步下單的方式做秒殺系統(tǒng)沒(méi)出現(xiàn)大的問(wèn)題,那是因?yàn)槟銈兊拿霘⑾到y(tǒng)的并發(fā)量沒(méi)達(dá)到一定的量級(jí),也就是說(shuō),你們的秒殺系統(tǒng)的并發(fā)量其實(shí)并不高。
所以,很多所謂的秒殺系統(tǒng),存在著秒殺的業(yè)務(wù),但是稱不上真正的秒殺系統(tǒng),原因就在于他們使用的是同步的下單流程,限制了系統(tǒng)的并發(fā)流量。
之所以上線后沒(méi)出現(xiàn)太大的問(wèn)題,是因?yàn)橄到y(tǒng)的并發(fā)量不高,不足以壓死整個(gè)系統(tǒng)。
如果 12306、淘寶、天貓、京東、小米等大型商城的秒殺系統(tǒng)是這么玩的話,那么,他們的系統(tǒng)遲早會(huì)被玩死,他們的系統(tǒng)工程師不被開(kāi)除才怪!
所以,在秒殺系統(tǒng)中,這種同步處理下單的業(yè)務(wù)流程的方案是不可取的。
以上就是同步下單的整個(gè)流程操作,如果下單流程更加復(fù)雜的話,就會(huì)涉及到更多的業(yè)務(wù)操作。
異步下單流程:
既然同步下單流程的秒殺系統(tǒng)稱不上真正的秒殺系統(tǒng),那我們就需要采用異步的下單流程了。異步的下單流程不會(huì)限制系統(tǒng)的高并發(fā)流量。
①用戶發(fā)起秒殺請(qǐng)求
用戶發(fā)起秒殺請(qǐng)求后,商城服務(wù)會(huì)經(jīng)過(guò)如下業(yè)務(wù)流程。
檢測(cè)驗(yàn)證碼是否正確:用戶發(fā)起秒殺請(qǐng)求時(shí),會(huì)將驗(yàn)證碼一同發(fā)送過(guò)來(lái),系統(tǒng)會(huì)檢驗(yàn)驗(yàn)證碼是否有效,并且是否正確。
是否限流:系統(tǒng)會(huì)對(duì)用戶的請(qǐng)求進(jìn)行是否限流的判斷,這里,我們可以通過(guò)判斷消息隊(duì)列的長(zhǎng)度來(lái)進(jìn)行判斷。
因?yàn)槲覀儗⒂脩舻恼?qǐng)求放在了消息隊(duì)列中,消息隊(duì)列中堆積的是用戶的請(qǐng)求,我們可以根據(jù)當(dāng)前消息隊(duì)列中存在的待處理的請(qǐng)求數(shù)量來(lái)判斷是否需要對(duì)用戶的請(qǐng)求進(jìn)行限流處理。
例如,在秒殺活動(dòng)中,我們出售 1000 件商品,此時(shí)在消息隊(duì)列中存在 1000 個(gè)請(qǐng)求,如果后續(xù)仍然有用戶發(fā)起秒殺請(qǐng)求,則后續(xù)的請(qǐng)求我們可以不再處理,直接向用戶返回商品已售完的提示。
所以,使用限流后,我們可以更快的處理用戶的請(qǐng)求和釋放連接的資源。
發(fā)送 MQ:用戶的秒殺請(qǐng)求通過(guò)前面的驗(yàn)證后,我們就可以將用戶的請(qǐng)求參數(shù)等信息發(fā)送到 MQ 中進(jìn)行異步處理,同時(shí),向用戶響應(yīng)結(jié)果信息。
在商城服務(wù)中,會(huì)有專(zhuān)門(mén)的異步任務(wù)處理模塊來(lái)消費(fèi)消息隊(duì)列中的請(qǐng)求,并處理后續(xù)的異步流程。
在用戶發(fā)起秒殺請(qǐng)求時(shí),異步下單流程比同步下單流程處理的業(yè)務(wù)操作更少,它將后續(xù)的操作通過(guò) MQ 發(fā)送給異步處理模塊進(jìn)行處理,并迅速向用戶返回響應(yīng)結(jié)果,釋放請(qǐng)求連接。
②異步處理
我們可以將下單流程的如下操作進(jìn)行異步處理:
- 判斷活動(dòng)是否已經(jīng)結(jié)束
- 判斷本次請(qǐng)求是否處于系統(tǒng)黑名單,為了防止電商領(lǐng)域同行的惡意競(jìng)爭(zhēng)可以為系統(tǒng)增加黑名單機(jī)制,將惡意的請(qǐng)求放入系統(tǒng)的黑名單中。可以使用攔截器統(tǒng)計(jì)訪問(wèn)頻次來(lái)實(shí)現(xiàn)。
- 扣減緩存中的秒殺商品的庫(kù)存數(shù)量。
- 生成秒殺 Token,這個(gè) Token 是綁定當(dāng)前用戶和當(dāng)前秒殺活動(dòng)的,只有生成了秒殺 Token 的請(qǐng)求才有資格進(jìn)行秒殺活動(dòng)。
這里我們引入了異步處理機(jī)制,在異步處理中,系統(tǒng)使用多少資源,分配多少線程來(lái)處理相應(yīng)的任務(wù),是可以進(jìn)行控制的。
③短輪詢查詢秒殺結(jié)果
這里,可以采取客戶端短輪詢查詢是否獲得秒殺資格的方案。例如,客戶端可以每隔 3 秒鐘輪詢請(qǐng)求服務(wù)器,查詢是否獲得秒殺資格。
這里,我們?cè)诜?wù)器的處理就是判斷當(dāng)前用戶是否存在秒殺 Token,如果服務(wù)器為當(dāng)前用戶生成了秒殺 Token,則當(dāng)前用戶存在秒殺資格。
否則繼續(xù)輪詢查詢,直到超時(shí)或者服務(wù)器返回商品已售完或者無(wú)秒殺資格等信息為止。
采用短輪詢查詢秒殺結(jié)果時(shí),在頁(yè)面上我們同樣可以提示用戶排隊(duì)處理中,但是此時(shí)客戶端會(huì)每隔幾秒輪詢服務(wù)器查詢秒殺資格的狀態(tài),相比于同步下單流程來(lái)說(shuō),無(wú)需長(zhǎng)時(shí)間占用請(qǐng)求連接。
此時(shí),可能會(huì)有網(wǎng)友會(huì)問(wèn):采用短輪詢查詢的方式,會(huì)不會(huì)存在直到超時(shí)也查詢不到是否具有秒殺資格的狀態(tài)呢?
答案是:有可能!這里我們?cè)囅胍幌旅霘⒌恼鎸?shí)場(chǎng)景,商家參加秒殺活動(dòng)本質(zhì)上不是為了賺錢(qián),而是提升商品的銷(xiāo)量和商家的知名度,吸引更多的用戶來(lái)買(mǎi)自己的商品。
所以,我們不必保證用戶能夠 100% 的查詢到是否具有秒殺資格的狀態(tài)。
④秒殺結(jié)算
驗(yàn)證下單 Token:客戶端提交秒殺結(jié)算時(shí),會(huì)將秒殺 Token 一同提交到服務(wù)器,商城服務(wù)會(huì)驗(yàn)證當(dāng)前的秒殺 Token 是否有效。
加入秒殺購(gòu)物車(chē):商城服務(wù)在驗(yàn)證秒殺 Token 合法并有效后,會(huì)將用戶秒殺的商品添加到秒殺購(gòu)物車(chē)。
⑤提交訂單
訂單入庫(kù):將用戶提交的訂單信息保存到數(shù)據(jù)庫(kù)中。
刪除 Token:秒殺商品訂單入庫(kù)成功后,刪除秒殺 Token。
這里大家可以思考一個(gè)問(wèn)題:我們?yōu)槭裁粗辉诋惒较聠瘟鞒痰姆凵糠植捎卯惒教幚恚鴽](méi)有在其他部分采取異步削峰和填谷的措施呢?
這是因?yàn)樵诋惒较聠瘟鞒痰脑O(shè)計(jì)中,無(wú)論是在產(chǎn)品設(shè)計(jì)上還是在接口設(shè)計(jì)上,我們?cè)谟脩舭l(fā)起秒殺請(qǐng)求階段對(duì)用戶的請(qǐng)求進(jìn)行了限流操作,可以說(shuō),系統(tǒng)的限流操作是非常前置的。
在用戶發(fā)起秒殺請(qǐng)求時(shí)進(jìn)行了限流,系統(tǒng)的高峰流量已經(jīng)被平滑解決了,再往后走,其實(shí)系統(tǒng)的并發(fā)量和系統(tǒng)流量并不是非常高了。
所以,網(wǎng)上很多的文章和帖子中在介紹秒殺系統(tǒng)時(shí),說(shuō)是在下單時(shí)使用異步削峰來(lái)進(jìn)行一些限流操作,那都是在扯淡!
因?yàn)橄聠尾僮髟谡麄€(gè)秒殺系統(tǒng)的流程中屬于比較靠后的操作了,限流操作一定要前置處理,在秒殺業(yè)務(wù)后面的流程中做限流操作是沒(méi)啥卵用的。
高并發(fā)“黑科技”與致勝奇招
假設(shè),在秒殺系統(tǒng)中我們使用 Redis 實(shí)現(xiàn)緩存,假設(shè) Redis 的讀寫(xiě)并發(fā)量在 5 萬(wàn)左右。
我們的商城秒殺業(yè)務(wù)需要支持的并發(fā)量在 100 萬(wàn)左右。如果這 100 萬(wàn)的并發(fā)全部打入 Redis 中,Redis 很可能就會(huì)掛掉,那么,我們?nèi)绾谓鉀Q這個(gè)問(wèn)題呢?
接下來(lái),我們就一起來(lái)探討這個(gè)問(wèn)題。在高并發(fā)的秒殺系統(tǒng)中,如果采用 Redis 緩存數(shù)據(jù),則 Redis 緩存的并發(fā)處理能力是關(guān)鍵,因?yàn)楹芏嗟那熬Y操作都需要訪問(wèn) Redis。
而異步削峰只是基本的操作,關(guān)鍵還是要保證 Redis 的并發(fā)處理能力。
解決這個(gè)問(wèn)題的關(guān)鍵思想就是:分而治之,將商品庫(kù)存分開(kāi)放。
暗度陳倉(cāng)
我們?cè)?Redis 中存儲(chǔ)秒殺商品的庫(kù)存數(shù)量時(shí),可以將秒殺商品的庫(kù)存進(jìn)行“分割”存儲(chǔ)來(lái)提升 Redis 的讀寫(xiě)并發(fā)量。
例如,原來(lái)的秒殺商品的 id 為 10001,庫(kù)存為 1000 件,在 Redis 中的存儲(chǔ)為(10001, 1000),我們將原有的庫(kù)存分割為 5 份,則每份的庫(kù)存為 200 件。
此時(shí),我們?cè)?Redis 中存儲(chǔ)的信息為(10001_0, 200),(10001_1, 200),(10001_2, 200),(10001_3, 200),(10001_4, 200)。
此時(shí),我們將庫(kù)存進(jìn)行分割后,每個(gè)分割后的庫(kù)存使用商品 id 加上一個(gè)數(shù)字標(biāo)識(shí)來(lái)存儲(chǔ)。
這樣,在對(duì)存儲(chǔ)商品庫(kù)存的每個(gè) Key 進(jìn)行 Hash 運(yùn)算時(shí),得出的 Hash 結(jié)果是不同的。
這就說(shuō)明,存儲(chǔ)商品庫(kù)存的 Key 有很大概率不在 Redis 的同一個(gè)槽位中,這就能夠提升 Redis 處理請(qǐng)求的性能和并發(fā)量。
分割庫(kù)存后,我們還需要在 Redis 中存儲(chǔ)一份商品 id 和分割庫(kù)存后的 Key 的映射關(guān)系,此時(shí)映射關(guān)系的 Key 為商品的 id,也就是 10001。
Value 為分割庫(kù)存后存儲(chǔ)庫(kù)存信息的 Key,也就是 10001_0,10001_1,10001_2,10001_3,10001_4。在 Redis 中我們可以使用 List 來(lái)存儲(chǔ)這些值。
在真正處理庫(kù)存信息時(shí),我們可以先從 Redis 中查詢出秒殺商品對(duì)應(yīng)的分割庫(kù)存后的所有 Key,同時(shí)使用 AtomicLong 來(lái)記錄當(dāng)前的請(qǐng)求數(shù)量。
使用請(qǐng)求數(shù)量對(duì)從 Redis 中查詢出的秒殺商品對(duì)應(yīng)的分割庫(kù)存后的所有 Key 的長(zhǎng)度進(jìn)行求模運(yùn)算,得出的結(jié)果為 0,1,2,3,4。
再在前面拼接上商品 id 就可以得出真正的庫(kù)存緩存的 Key。此時(shí),就可以根據(jù)這個(gè) Key 直接到 Redis 中獲取相應(yīng)的庫(kù)存信息。
移花接木
在高并發(fā)業(yè)務(wù)場(chǎng)景中,我們可以直接使用 Lua 腳本庫(kù)(OpenResty)從負(fù)載均衡層直接訪問(wèn)緩存。
這里,我們思考一個(gè)場(chǎng)景:如果在秒殺業(yè)務(wù)場(chǎng)景中,秒殺的商品被瞬間搶購(gòu)一空。
此時(shí),用戶再發(fā)起秒殺請(qǐng)求時(shí),如果系統(tǒng)由負(fù)載均衡層請(qǐng)求應(yīng)用層的各個(gè)服務(wù),再由應(yīng)用層的各個(gè)服務(wù)訪問(wèn)緩存和數(shù)據(jù)庫(kù)。
其實(shí),本質(zhì)上已經(jīng)沒(méi)有任何意義了,因?yàn)樯唐芬呀?jīng)賣(mài)完了,再通過(guò)系統(tǒng)的應(yīng)用層進(jìn)行層層校驗(yàn)已經(jīng)沒(méi)有太多意義了!!
而應(yīng)用層的并發(fā)訪問(wèn)量是以百為單位的,這又在一定程度上會(huì)降低系統(tǒng)的并發(fā)度。
為了解決這個(gè)問(wèn)題,此時(shí),我們可以在系統(tǒng)的負(fù)載均衡層取出用戶發(fā)送請(qǐng)求時(shí)攜帶的用戶 id,商品 id 和秒殺活動(dòng) id 等信息,直接通過(guò) Lua 腳本等技術(shù)來(lái)訪問(wèn)緩存中的庫(kù)存信息。
如果秒殺商品的庫(kù)存小于或者等于 0,則直接返回用戶商品已售完的提示信息,而不用再經(jīng)過(guò)應(yīng)用層的層層校驗(yàn)了。
針對(duì)這個(gè)架構(gòu),我們可以參見(jiàn)本文中的電商系統(tǒng)的架構(gòu)圖(正文開(kāi)始的第一張圖)。
寫(xiě)在最后
最后,附上并發(fā)編程需要掌握的核心技能知識(shí)圖,祝大家在學(xué)習(xí)并發(fā)編程時(shí),少走彎路。
后記:記住你比別人強(qiáng)的地方,不是你做過(guò)多少年的 CRUD 工作,而是你比別人掌握了更多深入的技能。
不要總停留在 CRUD 的表面工作,理解并掌握底層原理并熟悉源碼實(shí)現(xiàn),并形成自己的抽象思維能力,做到靈活運(yùn)用,才是你突破瓶頸,脫穎而出的重要方向!
你在刷抖音,玩游戲的時(shí)候,別人都在這里學(xué)習(xí),成長(zhǎng),提升,人與人最大的差距其實(shí)就是思維。你可能不信,優(yōu)秀的人,總是在一起。。
作者:冰河技術(shù)
編輯:陶家龍
出處:轉(zhuǎn)載自微信公眾號(hào)冰河技術(shù)(hacker-binghe)






































