商品庫(kù)存扣減方案設(shè)計(jì)

引言:在庫(kù)存的變動(dòng)中锌唾,最關(guān)鍵的節(jié)點(diǎn)是庫(kù)存的扣減,在什么時(shí)候扣減庫(kù)存非常重要触徐。目前通用的庫(kù)存扣減方案有以下幾種

  1. 支付后扣減庫(kù)存咪鲜,缺點(diǎn):成功下單的用戶(hù),到支付時(shí)沒(méi)有庫(kù)存可用撞鹉,導(dǎo)致交易失敗疟丙。

  2. 下單時(shí)就減庫(kù)存,訂單取消再把庫(kù)存加回來(lái)鸟雏,缺點(diǎn):惡意刷單不支付導(dǎo)致大量庫(kù)存被占用享郊,影響商品售賣(mài)。

  3. 下單時(shí)先預(yù)減庫(kù)存(對(duì)應(yīng)數(shù)據(jù)庫(kù) 占用庫(kù)存加庫(kù)存操作),支付完成時(shí) 釋放占用庫(kù)存(減操作)孝鹊,扣減可用庫(kù)存炊琉。 同時(shí)商品在下單時(shí)判斷商品的實(shí)際可售庫(kù)存 = 可用庫(kù)存 - 占用庫(kù)存,如果 > 0,表示可以下訂單,這樣就不會(huì)導(dǎo)致 下單成功苔咪,但是支付時(shí)沒(méi)有庫(kù)存導(dǎo)致失敗的場(chǎng)景锰悼。

具體方案

  • 訂單創(chuàng)建時(shí),通過(guò)調(diào)用商品接口預(yù)占庫(kù)存团赏,如果預(yù)占庫(kù)存成功箕般,則創(chuàng)建訂單,如果預(yù)占庫(kù)存失敗舔清,則提示商品庫(kù)存不足丝里。這個(gè)接口必須是同步實(shí)時(shí)的,因?yàn)橛唵我鶕?jù)預(yù)占庫(kù)存的結(jié)果來(lái)判斷訂單能否創(chuàng)建鸠踪。
  • 訂單支付丙者、取消時(shí),發(fā)送mq消息到商品营密,商品異步消費(fèi)消息械媒,根據(jù)消息的類(lèi)別去操作庫(kù)存。如果是未支付取消訂單评汰,則釋放預(yù)占用庫(kù)存纷捞。如果是支付后退款,則需要將可用庫(kù)存加回來(lái)被去。如果是成功支付主儡,則釋放預(yù)占庫(kù)存,并同時(shí)扣減可用庫(kù)存惨缆。

需要注意的問(wèn)題

  • 商品超賣(mài)問(wèn)題
    正常情況下糜值,一個(gè)訂單過(guò)來(lái),其中A商品買(mǎi)了n個(gè)坯墨,那么我們操作數(shù)據(jù)庫(kù)的時(shí)候寂汇,直接 set stock = stock -n 。這種當(dāng)然是有問(wèn)題的捣染,有可能會(huì)超賣(mài)導(dǎo)致商品庫(kù)存為負(fù)數(shù)骄瓣。當(dāng)然我們可以在更新db之前,判斷庫(kù)存數(shù)是否 > n耍攘,如果大于n榕栏,再去扣減庫(kù)存。這總當(dāng)然可以蕾各,不過(guò)高并發(fā)下扒磁,可能依然會(huì)導(dǎo)致超賣(mài)。當(dāng)然你可以加鎖去保證單線(xiàn)程式曲,不過(guò)這樣就導(dǎo)致了接口的性能下降渗磅。其實(shí)sql 可以換個(gè)寫(xiě)法 set stock = stock -n where stock >= n。 這樣利用了數(shù)據(jù)庫(kù)的天然寫(xiě)法保證了商品不超賣(mài)检访。
  • 高并發(fā)下的接口性能問(wèn)題
    步驟一訂單創(chuàng)建實(shí)時(shí)調(diào)用商品占用庫(kù)存接口始鱼,因?yàn)槭菍?shí)時(shí)調(diào)用,如果是高并發(fā)情況下脆贵,對(duì)于db占用庫(kù)存的更新操作可能就會(huì)成為性能瓶頸(訂單支付或者取消時(shí)医清,因?yàn)樽吡讼㈥?duì)列異步更新數(shù)據(jù)庫(kù),就不存在性能問(wèn)題)卖氨。
    如果解決這個(gè)問(wèn)題呢会烙?業(yè)界常用的做法是,將商品的可用庫(kù)存放到redis中筒捺,當(dāng)訂單創(chuàng)建調(diào)用占用庫(kù)存接口時(shí)柏腻,我們可以利用redis去抗并發(fā),并且redis的命令支持原子性系吭。

1.創(chuàng)建訂單扣減緩存中的可用庫(kù)存

緩存中更新庫(kù)存和我們?nèi)ジ聰?shù)據(jù)庫(kù)時(shí)遇到的場(chǎng)景一樣五嫂,因?yàn)橐袛鄮?kù)存是否大于下單購(gòu)買(mǎi)數(shù)的邏輯要保持原子性,同時(shí)一個(gè)訂單中需要判斷多個(gè)商品的庫(kù)存也是需要原子性肯尺,可以結(jié)合lua腳本來(lái)實(shí)現(xiàn)沃缘。

  • 首先根據(jù)訂單明細(xì)id查詢(xún)扣減流水,是否已經(jīng)操作過(guò)则吟,做冪等性校驗(yàn)

  • 然后查詢(xún)sku的剩余庫(kù)存槐臀,并根據(jù)下單購(gòu)買(mǎi)數(shù)做校驗(yàn),只要有一個(gè)sku 數(shù)量不足氓仲,則返回失敗

  • 修改緩存中的剩余庫(kù)存數(shù)

  • 緩存中插入扣減流水記錄

2.支付成功后消息隊(duì)列異步更新數(shù)據(jù)庫(kù)中的可用庫(kù)存

3.訂單未支付取消時(shí)則需要將緩存中的庫(kù)存加回來(lái)水慨。根據(jù)訂單明細(xì)id查詢(xún)扣減流水,有扣減流水敬扛,則繼續(xù)查詢(xún)出訂單中所有sku商品的庫(kù)存晰洒,將扣減的庫(kù)存再加回來(lái)。如果沒(méi)有扣減流水舔哪,則跳過(guò)不處理欢顷。

4、訂單已支付退款時(shí)捉蚤,需要同時(shí)更新緩存中的庫(kù)存和db中的庫(kù)存抬驴。

缺點(diǎn):上面我們說(shuō)的用lua腳本執(zhí)行命令,如果一個(gè)訂單中的多個(gè)商品缆巧,布持,一部分成功,一部分扣減庫(kù)存失敗陕悬,那么是無(wú)法進(jìn)行回滾操作的题暖,雖然這種可能性很小,所以這種方案我們只能盡量保證redis集群的高可用。以上方案解決了高并發(fā)下的接口性能瓶頸胧卤,但是因?yàn)槠鋸?fù)雜性有可能會(huì)導(dǎo)致redis中可用庫(kù)存和數(shù)據(jù)庫(kù)中的可用庫(kù)存不一致(這里說(shuō)的不一致是指沒(méi)有未支付訂單占用庫(kù)存的情況)唯绍,我們可能還需要定時(shí)任務(wù)去定時(shí)維護(hù)redis中可用庫(kù)存和數(shù)據(jù)庫(kù)中可用庫(kù)存的一致性,用數(shù)據(jù)庫(kù)中的庫(kù)存 - 未支付訂單的占用庫(kù)存枝誊,然后更新到redis中

總結(jié):以上基于緩存扣減庫(kù)存况芒,大部分情況是對(duì)一些活動(dòng)的秒殺商品可能才會(huì)有如此高的并發(fā),正常情況下也不可能將所用商戶(hù)的所有商品庫(kù)存都緩存到redis中叶撒,這樣也不現(xiàn)實(shí)绝骚。所以絕大部分流量不高的情況下,我們可以采用數(shù)據(jù)庫(kù)占用庫(kù)存的方式,這種方式簡(jiǎn)單高效祠够,不易出錯(cuò)压汪。對(duì)于一些活動(dòng)商品,我們則可以單獨(dú)走緩存扣減可用庫(kù)存的方式古瓤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末止剖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子湿滓,更是在濱河造成了極大的恐慌滴须,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,002評(píng)論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叽奥,死亡現(xiàn)場(chǎng)離奇詭異扔水,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)朝氓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門(mén)魔市,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人赵哲,你說(shuō)我怎么就攤上這事待德。” “怎么了枫夺?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,787評(píng)論 0 365
  • 文/不壞的土叔 我叫張陵将宪,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我橡庞,道長(zhǎng)较坛,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,237評(píng)論 1 300
  • 正文 為了忘掉前任扒最,我火速辦了婚禮丑勤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吧趣。我一直安慰自己法竞,他們只是感情好耙厚,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,237評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著岔霸,像睡著了一般薛躬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秉剑,一...
    開(kāi)封第一講書(shū)人閱讀 52,821評(píng)論 1 314
  • 那天泛豪,我揣著相機(jī)與錄音,去河邊找鬼侦鹏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛臀叙,可吹牛的內(nèi)容都是我干的略水。 我是一名探鬼主播,決...
    沈念sama閱讀 41,236評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼劝萤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼渊涝!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起床嫌,我...
    開(kāi)封第一講書(shū)人閱讀 40,196評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤跨释,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后厌处,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鳖谈,經(jīng)...
    沈念sama閱讀 46,716評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,794評(píng)論 3 343
  • 正文 我和宋清朗相戀三年阔涉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缆娃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,928評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瑰排,死狀恐怖贯要,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情椭住,我是刑警寧澤崇渗,帶...
    沈念sama閱讀 36,583評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站京郑,受9級(jí)特大地震影響宅广,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜傻挂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,264評(píng)論 3 336
  • 文/蒙蒙 一副砍、第九天 我趴在偏房一處隱蔽的房頂上張望刊苍。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,755評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至电禀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間笤休,已是汗流浹背尖飞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,869評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留店雅,地道東北人政基。 一個(gè)月前我還...
    沈念sama閱讀 49,378評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像闹啦,于是被迫代替她去往敵國(guó)和親沮明。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,937評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容