欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談Redis在秒殺場(chǎng)景的作用

 更新時(shí)間:2023年01月25日 10:05:54   作者:JavaEdge.  
本文主要介紹了淺談Redis在秒殺場(chǎng)景的作用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

秒殺業(yè)務(wù)特點(diǎn):限時(shí)限量,業(yè)務(wù)系統(tǒng)要處理瞬時(shí)高并發(fā)請(qǐng)求,Redis是必需品。

秒殺可分成秒殺前、秒殺中和秒殺后三階段,每個(gè)階段的請(qǐng)求處理需求不同,Redis具體在秒殺場(chǎng)景的哪個(gè)環(huán)節(jié)起到作用呢?

1 秒殺負(fù)載特征

秒殺商品的庫(kù)存量<<購(gòu)買該商品的用戶數(shù),且會(huì)限定用戶只能在一定時(shí)間段內(nèi)購(gòu)買。
這給秒殺系統(tǒng)帶來(lái)兩個(gè)明顯負(fù)載特征:

1.1 瞬時(shí)并發(fā)訪問量很高

一般DB每秒只能支撐k級(jí)并發(fā),而Redis并發(fā)能達(dá)到w級(jí)。所以,當(dāng)大量并發(fā)請(qǐng)求涌入秒殺系統(tǒng)時(shí),要使用Redis先攔截大部分請(qǐng)求,避免大量請(qǐng)求直接發(fā)給DB

1.2 讀多寫少

讀還是簡(jiǎn)單的查詢操作。秒殺下,用戶需先查驗(yàn)商品是否還有庫(kù)存(即根據(jù)商品ID查詢?cè)搸?kù)存量),只有庫(kù)存有余量時(shí),秒殺系統(tǒng)才能進(jìn)行庫(kù)存扣減、下單??杀镜鼐彺姹4鎺?kù)存是否為 0 的標(biāo)識(shí),避免再請(qǐng)求 redis。

庫(kù)存查驗(yàn)操作是典型KV查詢,Redis正滿足。但秒殺只有小部分用戶能成功下單,所以:
商品庫(kù)存查詢操作(讀操作)>>庫(kù)存扣減、下單操作(寫操作)

一般把秒殺活動(dòng)分成三個(gè)階段:

2 秒殺階段

2.1 秒殺前

用戶不斷刷新商品詳情頁(yè),導(dǎo)致詳情頁(yè)瞬時(shí)請(qǐng)求量猛增。

一般盡量靜態(tài)化商品詳情頁(yè)的頁(yè)面元素,然后使用CDN或?yàn)g覽器緩存這些靜態(tài)化元素。
秒殺前的大量請(qǐng)求可直接由CDN或?yàn)g覽器緩存服務(wù),不會(huì)到達(dá)服務(wù)端。

2.2 秒殺中

大量用戶點(diǎn)擊商品詳情頁(yè)上的秒殺按鈕,會(huì)產(chǎn)生大量的并發(fā)請(qǐng)求查詢庫(kù)存。一旦某個(gè)請(qǐng)求查詢到有庫(kù)存,緊接著系統(tǒng)就會(huì)進(jìn)行庫(kù)存扣減。然后,系統(tǒng)會(huì)生成實(shí)際訂單,并進(jìn)行后續(xù)處理,例如訂單支付和物流服務(wù)。如果請(qǐng)求查不到庫(kù)存,就會(huì)返回。用戶通常會(huì)繼續(xù)點(diǎn)擊秒殺按鈕,繼續(xù)查詢庫(kù)存。

該階段主要操作:

  • 庫(kù)存查驗(yàn)
  • 庫(kù)存扣減
  • 訂單處理

每個(gè)秒殺請(qǐng)求都會(huì)查詢庫(kù)存,而請(qǐng)求只有查到有庫(kù)存余量,后續(xù)的庫(kù)存扣減和訂單處理才會(huì)被執(zhí)行。所以,該階段最大并發(fā)壓力在庫(kù)存查驗(yàn)。就需使用Redis保存庫(kù)存量,請(qǐng)求直接從Redis讀庫(kù)存并查驗(yàn)。

庫(kù)存扣減和訂單處理是否都可交給后端DB執(zhí)行?

訂單處理可在DB執(zhí)行,但庫(kù)存扣減操作,不能交給DB。

為何非在DB處理訂單呢?

訂單處理涉及支付、商品出庫(kù)、物流等多個(gè)關(guān)聯(lián)操作,這些操作本身涉及DB中的多張表,要保證事務(wù)性,需在DB完成。
訂單處理時(shí),請(qǐng)求壓力已不大,DB完全可支撐。

為啥庫(kù)存扣減操作不能在DB執(zhí)行

一旦請(qǐng)求查到有庫(kù)存,即發(fā)送該請(qǐng)求的用戶獲得商品購(gòu)買資格,用戶就會(huì)下單了。同時(shí),商品庫(kù)存余量也需-1。

若把庫(kù)存扣減的操作放到DB,會(huì)帶來(lái)風(fēng)險(xiǎn):

額外開銷
Redis保存庫(kù)存量,而庫(kù)存量最新值又是DB在維護(hù),所以DB更新后,還要和Redis進(jìn)行同步,這增加額外操作邏輯

下單量>實(shí)際庫(kù)存量,超賣!
由于DB處理性能較慢,無(wú)法及時(shí)更新庫(kù)存余量,可能導(dǎo)致大量庫(kù)存查驗(yàn)請(qǐng)求讀到舊庫(kù)存值,并下單。就會(huì)出現(xiàn)下單數(shù)量>實(shí)際庫(kù)存量,導(dǎo)致超賣

所以,要在Redis進(jìn)行庫(kù)存扣減:

  • 當(dāng)庫(kù)存查驗(yàn)完成后,一旦庫(kù)存有余量,立即在Redis扣庫(kù)存
  • 為避免請(qǐng)求查詢到舊庫(kù)存值,庫(kù)存查驗(yàn)、庫(kù)存扣減兩個(gè)操作需保證原子性

秒殺中需要Redis參與的兩個(gè)環(huán)節(jié):

2.3 秒殺結(jié)束后

該階段,可能還有部分用戶刷新商品詳情頁(yè),嘗試等待有其他用戶退單。而已成功下單的用戶會(huì)刷新訂單詳情,跟蹤訂單進(jìn)度。
不過,此階段的用戶請(qǐng)求量已下降很多,服務(wù)器端一般都能支撐。

3 Redis可支撐秒殺的特性

3.1 支持高并發(fā)

Redis先天支持。且若有多個(gè)秒殺商品,也可使用切片集群,用不同實(shí)例保存不同商品的庫(kù)存,避免使用單實(shí)例導(dǎo)致所有秒殺請(qǐng)求都集中在一個(gè)實(shí)例。
使用切片集群時(shí),先CRC計(jì)算不同秒殺商品K對(duì)應(yīng)Slot,然后在分配Slot和實(shí)例對(duì)應(yīng)關(guān)系時(shí),才能把不同秒殺商品對(duì)應(yīng)的Slot分配到不同實(shí)例保存。

3.2 保證庫(kù)存查驗(yàn)和庫(kù)存扣減的原子性

使用Redis的原子操作或分布式鎖。

4 基于原子操作支撐秒殺

秒殺中的一個(gè)商品的庫(kù)存對(duì)應(yīng)兩個(gè)信息:

  • 總庫(kù)存量
  • 已秒殺量

這種數(shù)據(jù)模型正好一個(gè)key(商品ID)對(duì)應(yīng)兩個(gè)屬性(總庫(kù)存量和已秒殺量),可用Hash保存:

key: itemID
value: {total: N, ordered: M}

itemID 商品編號(hào)total,總庫(kù)存量ordered,已秒殺量

因?yàn)閹?kù)存查驗(yàn)、庫(kù)存扣減這兩個(gè)操作要保證一起執(zhí)行,一個(gè)直接的方法就是使用Redis的原子操作。

庫(kù)存查驗(yàn)、庫(kù)存扣減是兩個(gè)操作,需Lua腳本保證原子執(zhí)行:

#獲取商品庫(kù)存信息            
local counts = redis.call("HMGET", KEYS[1], "total", "ordered");
#將總庫(kù)存轉(zhuǎn)換為數(shù)值
local total = tonumber(counts[1])
#將已被秒殺的庫(kù)存轉(zhuǎn)換為數(shù)值
local ordered = tonumber(counts[2])  
#如果當(dāng)前請(qǐng)求的庫(kù)存量加上已被秒殺的庫(kù)存量仍然小于總庫(kù)存量,就可以更新庫(kù)存         
if ordered + k <= total then
    #更新已秒殺的庫(kù)存量
    redis.call("HINCRBY",KEYS[1],"ordered",k)                              return k;  
end               
return 0

然后就能在Redis客戶端,使用EVAL命令執(zhí)行腳本??蛻舳烁鶕?jù)腳本返回值,確定秒殺是否成功:

  • 返回值k,成功
  • 0,失敗

5 基于分布式鎖支撐秒殺

讓客戶端向Redis申請(qǐng)分布式鎖,拿到鎖的客戶端才能執(zhí)行庫(kù)存查驗(yàn)、庫(kù)存扣減。
這樣大量秒殺請(qǐng)求就會(huì)在爭(zhēng)奪分布式鎖時(shí)被過濾掉。
庫(kù)存查驗(yàn)、扣減也不用原子操作了,因?yàn)槎鄠€(gè)并發(fā)客戶端只有一個(gè)客戶端能夠拿到鎖,已保證客戶端并發(fā)訪問的互斥性。

// 使用商品ID作為key
key = itemID
// 使用客戶端唯一標(biāo)識(shí)作為value
val = clientUniqueID
//申請(qǐng)分布式鎖,Timeout是超時(shí)時(shí)間
lock =acquireLock(key, val, Timeout)
//當(dāng)拿到鎖后,才能進(jìn)行庫(kù)存查驗(yàn)和扣減
if(lock == True) {
   //庫(kù)存查驗(yàn)和扣減
   availStock = DECR(key, k)
   //庫(kù)存已經(jīng)扣減完了,釋放鎖,返回秒殺失敗
   if (availStock < 0) {
      releaseLock(key, val)
      return error
   }
   //庫(kù)存扣減成功,釋放鎖
   else{
     releaseLock(key, val)
     //訂單處理
   }
}
//沒有拿到鎖,直接返回
else
   return

使用分布式鎖時(shí),客戶端要先向Redis請(qǐng)求鎖,只有請(qǐng)求到鎖,才能進(jìn)行庫(kù)存查驗(yàn)等操作,這樣客戶端在爭(zhēng)搶分布式鎖時(shí),大部分秒殺請(qǐng)求本身就會(huì)因?yàn)閾尣坏芥i而被攔截。

推薦使用切片集群中的不同實(shí)例來(lái)分別保存分布式鎖和商品庫(kù)存信息。秒殺請(qǐng)求會(huì)先訪問保存分布式鎖的實(shí)例。若客戶端沒拿到鎖,這些客戶端就不會(huì)查詢商品庫(kù)存,減輕保存庫(kù)存信息的實(shí)例的壓力。

6 總結(jié)

秒殺系統(tǒng)是個(gè)系統(tǒng)性工程,Redis實(shí)現(xiàn)對(duì)庫(kù)存查驗(yàn)、扣減環(huán)節(jié)的支撐。

此外,還有環(huán)節(jié)需要處理:

前端靜態(tài)頁(yè)面的設(shè)計(jì)

秒殺頁(yè)面上能靜態(tài)化處理的頁(yè)面元素,要盡量靜態(tài)化,充分利用CDN或?yàn)g覽器緩存服務(wù)秒殺開始前的請(qǐng)求

請(qǐng)求攔截和流控

在秒殺系統(tǒng)的接入層,對(duì)惡意請(qǐng)求進(jìn)行攔截,避免對(duì)系統(tǒng)的惡意攻擊,例如使用黑名單禁止惡意IP進(jìn)行訪問。如果Redis實(shí)例的訪問壓力過大,為了避免實(shí)例崩潰,我們也需要在接入層進(jìn)行限流,控制進(jìn)入秒殺系統(tǒng)的請(qǐng)求數(shù)量。

庫(kù)存信息過期時(shí)間處理

Redis中保存的庫(kù)存信息其實(shí)是數(shù)據(jù)庫(kù)的緩存,為了避免緩存擊穿問題,不要給庫(kù)存信息設(shè)置過期時(shí)間。
數(shù)據(jù)庫(kù)訂單異常處理。如果數(shù)據(jù)庫(kù)沒能成功處理訂單,可以增加訂單重試功能,保證訂單最終能被成功處理。

資源隔離

秒殺活動(dòng)帶來(lái)的請(qǐng)求流量巨大,我們需要把秒殺商品的庫(kù)存信息用單獨(dú)的實(shí)例保存,而不要和日常業(yè)務(wù)系統(tǒng)的數(shù)據(jù)保存在同一個(gè)實(shí)例上,這樣可以避免干擾業(yè)務(wù)系統(tǒng)的正常運(yùn)行。

到此這篇關(guān)于淺談Redis在秒殺場(chǎng)景的作用的文章就介紹到這了,更多相關(guān)Redis 秒殺內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis高并發(fā)防止秒殺超賣實(shí)戰(zhàn)源碼解決方案

    Redis高并發(fā)防止秒殺超賣實(shí)戰(zhàn)源碼解決方案

    本文主要介紹了Redis高并發(fā)防止秒殺超賣實(shí)戰(zhàn)源碼解決方案,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Redis遠(yuǎn)程連接Redis客戶端的實(shí)現(xiàn)步驟

    Redis遠(yuǎn)程連接Redis客戶端的實(shí)現(xiàn)步驟

    本文主要介紹了Redis遠(yuǎn)程連接Redis客戶端的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 從一個(gè)小需求感受Redis的獨(dú)特魅力(需求設(shè)計(jì))

    從一個(gè)小需求感受Redis的獨(dú)特魅力(需求設(shè)計(jì))

    Redis在實(shí)際應(yīng)用中使用的非常廣泛,本篇文章就從一個(gè)簡(jiǎn)單的需求說(shuō)起,為你講述一個(gè)需求是如何從頭到尾開始做的,又是如何一步步完善的
    2019-12-12
  • Redis執(zhí)行Lua腳本的好處與示例代碼

    Redis執(zhí)行Lua腳本的好處與示例代碼

    Redis在2.6推出了腳本功能,允許開發(fā)者使用Lua語(yǔ)言編寫腳本傳到Redis中執(zhí)行。下面這篇文章主要給大家介紹了關(guān)于Redis執(zhí)行Lua腳本的好處與示例代碼,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-10-10
  • Redis大Key問題的解決方案

    Redis大Key問題的解決方案

    Redis中的大Key問題指的是某些鍵(key)所對(duì)應(yīng)的值(value)特別大或集合類數(shù)據(jù)結(jié)構(gòu)中元素?cái)?shù)量過多,大Key會(huì)導(dǎo)致讀取成本高、寫操作易阻塞、慢查詢和主從同步異常等問題,本文就來(lái)介紹一下如何解決,感興趣的可以了解一下
    2024-09-09
  • Redis安裝與使用方法小結(jié)

    Redis安裝與使用方法小結(jié)

    這篇文章主要介紹了Redis安裝與使用方法,結(jié)合實(shí)例形式分析了Redis數(shù)據(jù)庫(kù)的下載、安裝、啟動(dòng)、設(shè)置及相關(guān)使用操作注意事項(xiàng),需要的朋友可以參考下
    2018-04-04
  • Linux服務(wù)器快速安裝Redis6.0步驟示例詳解

    Linux服務(wù)器快速安裝Redis6.0步驟示例詳解

    這篇文章主要為大家介紹了Linux服務(wù)器快速安裝Redis6.0步驟示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Redis Cluster集群動(dòng)態(tài)擴(kuò)容的實(shí)現(xiàn)

    Redis Cluster集群動(dòng)態(tài)擴(kuò)容的實(shí)現(xiàn)

    本文主要介紹了Redis Cluster集群動(dòng)態(tài)擴(kuò)容的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • 使用lua+redis解決發(fā)多張券的并發(fā)問題

    使用lua+redis解決發(fā)多張券的并發(fā)問題

    這篇文章主要介紹了使用lua+redis解決發(fā)多張券的并發(fā)問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • 使用 Redis 流實(shí)現(xiàn)消息隊(duì)列的代碼

    使用 Redis 流實(shí)現(xiàn)消息隊(duì)列的代碼

    這篇文章主要介紹了使用 Redis 流實(shí)現(xiàn)消息隊(duì)列,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-11-11

最新評(píng)論