淺析「扣減庫存」的方案設計

這是悟空的第 108 篇原創文章前端

做者 | 悟空聊架構sql

來源 | 悟空聊架構(ID:PassJava666)數據庫

轉載請聯繫受權(微信ID:PassJava)後端

你好,我是悟空。緩存

上篇談到了秒殺設計的方案:微信

《我是一個秒殺請求,正在逃離這顆星球...》架構

今天咱們來探討下扣減庫存的方案。併發

生活中,咱們老是用各類電商 APP 搶購商品,可是庫存數是不多的,特別是秒殺場景,商品可能就一件,那如何保證不會出現超賣的狀況呢?分佈式

1、扣減庫存的三種方案

1.1 下單減庫存

用戶下單時減庫存高併發

優勢:實時減庫存,避免付款時因庫存不足減庫存的問題

缺點:惡意買家大量下單,將庫存用完,可是不付款,真正想買的人買不到

1.2 付款減庫存

下單頁面顯示最新的庫存,下單時不會當即減庫存,而是等到支付時纔會減庫存。

優勢:防止惡意買家大量下單用光庫存,避免下單減庫存的缺點

缺點:下單頁面顯示的庫存數可能不是最新的庫存數,而庫存數用完後,下單頁面的庫存數沒有刷新,出現下單數超過庫存數,若支付的訂單數超過庫存數,則會出現支付失敗。

1.3 預扣庫存

下單頁面顯示最新的庫存,下單後保留這個庫存一段時間(好比10分鐘),超過保留時間後,庫存釋放。若保留時間事後再支付,若是沒有庫存,則支付失敗。

優勢:結合下單減庫存的優勢,實時減庫存,且緩解惡意買家大量下單的問題,保留時間內未支付,則釋放庫存。

缺點:保留時間內,惡意買家大量下單將庫存用完。併發量很高的時候,依然會出現下單數超過庫存數。

2、如何解決惡意買家下單的問題

這裏的惡意買家指短期內大量下單,將庫存用完的買家。

2.1 限制用戶下單數量

優勢:限制惡意買家下單

缺點:用戶想要多買幾件,被限制了,會下降銷售量

2.2 標識惡意買家

經過標識用戶的設備 id 或者會員 id,將用戶加入黑名單,不足之處是有些用戶是模擬的,識別不出來是否是真正的惡意買家。

3、如何解決下單成功而支付失敗(庫存不足)的問題

3.1 備用庫存

商品庫存用完後,若是還有用戶支付,直接扣減備用庫存。

優勢:緩解部分用戶支付失敗的問題。

缺點:備用庫存只能緩解問題,不能從根本上解決問題。另外備用庫存針對普通商品能夠,針對特殊商品這種庫存少的,備用庫存量也不會很大,仍是會出現大量用戶下單成功卻因庫存不足而支付失敗的問題。

4、如何解決高併發下庫存超賣的場景

庫存超賣最簡單的解釋就是多成交了訂單而發不了貨。

場景

用戶 A 和 B 成功下單,在支付時扣減庫存,當前庫存數爲 10。因 A 和 B 查詢庫存時,都還有庫存數,因此 A 和 B 均可以付款。

A 和 B 同時支付,A 和 B 支付完成後,能夠看作兩個請求回調後臺系統扣減庫存,有兩個線程處理請求,兩個線程查詢出來的庫存數 inventory = 10

而後 A 線程更新最終庫存數 :

lastInventory = inventory - 1 = 9,

B 線程更新庫存數: 

lastInventory = inventory - 1 = 9。

而實際最終的庫存應是 8 纔對,這樣就出現庫存超賣的狀況,而發不出貨。

那如何解決庫存超賣的狀況呢?

如下方案都是基於數據庫層面的。有些同窗可能會問,是否是能夠用 Redis 分佈式鎖來,後面會講到。

方案一

SQL語句直接更新庫存,而不是先查詢出來,而後賦值

UPDATE [庫存表] SET 庫存數 - 1

方案二

SQL語句更新庫存時,若是扣減庫存後,庫存數爲負數,直接拋異常,利用事務的原子性進行自動回滾。

方案三

利用SQL語句更新庫存,防止庫存爲負數

UPDATE [庫存表] SET 庫存數 - 1 WHERE 庫存數 - 1 > 0

若是影響條數大於1,則表示扣減庫存成功,不然不更新庫存,並退款。

5、秒殺場景下如何扣減庫存

5.1 採用下單減庫存

因秒殺場景下,大部分用戶都是想直接購買商品的,能夠直接用下單減庫存。

大量用戶和惡意用戶都是同時進行的,區別是正經常使用戶會直接購買商品,惡意用戶雖然在競爭搶購的名額,可是獲取到的資格和普通用戶同樣,因此下單減庫存在秒殺場景下,惡意用戶下單並不能形成以前說的缺點。

並且下單直接扣減庫存,這個方案更簡單,在第一步就扣減庫存了。

5.2  Redis 緩存

查詢緩存要比查詢數據庫快,因此將庫存數放在緩存中,直接在緩存中扣減庫存。

若是併發很高,還能夠採起分佈式鎖的方案。分佈式鎖能夠參考我以前寫的兩篇文章:

《Redis 分佈式鎖|從青銅到鑽石的五種演進方案

《分佈式鎖中的王者方案 - Redisson》

5.3 限流

秒殺場景中,對請求作了不少限流操做,好比前端頁面的限流和後端令牌桶限流,真正到扣減庫存那一步時,請求數不多了。因此限流經常使用在秒殺方案中,感受能夠再寫一篇限流的文章了~

另外其實真實的項目中,用到了更多的機制來保證可以正常扣減庫存,本篇是拋磚引入,但願你們提出寶貴的建議和方案~。

贈送一張秒殺場景方案總結:

👍推薦閱讀:我是一個秒殺請求,正在逃離這顆星球...

- END -

寫了兩本 PDF, 回覆  分佈式  或  PDF  下 載。

個人 JVM 專欄已上架,回覆  JVM  領取

我是悟空,努力變強,變身超級賽亞人!

本文分享自微信公衆號 - 悟空聊架構(PassJava666)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索