這是悟空的第 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 緩存
查詢緩存要比查詢數據庫快,因此將庫存數放在緩存中,直接在緩存中扣減庫存。
若是併發很高,還能夠採起分佈式鎖的方案。分佈式鎖能夠參考我以前寫的兩篇文章:
5.3 限流
秒殺場景中,對請求作了不少限流操做,好比前端頁面的限流和後端令牌桶限流,真正到扣減庫存那一步時,請求數不多了。因此限流經常使用在秒殺方案中,感受能夠再寫一篇限流的文章了~
另外其實真實的項目中,用到了更多的機制來保證可以正常扣減庫存,本篇是拋磚引入,但願你們提出寶貴的建議和方案~。
贈送一張秒殺場景方案總結:
- END -
寫了兩本 PDF, 回覆 分佈式 或 PDF 下 載。
個人 JVM 專欄已上架,回覆 JVM 領取
我是悟空,努力變強,變身超級賽亞人!
本文分享自微信公衆號 - 悟空聊架構(PassJava666)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。