如何在直播平臺開發中,防止商品庫存扣除時超賣?

雲豹科技程式設計師發表於2021-12-22
直播平臺開發的商品購買過程,庫存的抵扣過程,一般操作如下:
1、select根據商品id查詢商品的庫存。 2、根據下單的數量,計算庫存是否足夠,如果存庫不足則丟擲庫存不足的異常,如果庫存足夠,則減去扣除的庫存得到最新的庫存剩餘值。 3、set設定最新的庫存剩餘值。
上述過程的虛擬碼如下:
// 根據商品id獲取商品剩餘庫存
select stock_remaing from stock_table where id=${goodsId};
 
// 操作庫存
// 比較庫存
if(stock_remaing <quantity){
   // 丟擲庫存不足的異常
}
else{
// 抵扣以後的庫存值
int new_stock=stock_remaing - quantity;
}
 
// 根據商品id設定計算後的庫存
update stock_table  set stock_remaing =${new_stock} id=${goodsId};

併發修改資料庫存超賣

如果直播平臺開發的資料庫事務隔離級別不是序列化(serializable),根據事務的特性,在併發修改的時候,可能會出現寫覆蓋的問題。假設,商品的剩餘庫存stock_remaing 為100,客戶A下單20,客戶B下單30,在併發扣庫存的時候,可能存在超賣。如果客戶A和客戶B同時獲取剩餘庫存為100,則會出現事務後提交的值會覆蓋前一個客戶提交的值,有可能剩餘的庫存是80或者70。流程如下:
如何在直播平臺開發中,防止商品庫存扣除時超賣?

加鎖更新存庫

為了在直播平臺開發的事務控制中,防止寫覆蓋,你會想到使用select for update的方式,將該商品的庫存鎖住,然後執行餘下的操作。流程如下:
如何在直播平臺開發中,防止商品庫存扣除時超賣?
以上,使用悲觀鎖方式,在分散式服務中,如果併發情況比較高的時候,扣減庫存的操作是序列操作,效率很低。

使用樂觀鎖的方式更新

在更新的時候,使用(CAS+版本號更新)+重試條件(重試次數或者重試時間限制)樂觀鎖的方式更新直播平臺開發庫存(樂觀鎖的操作過程可以參考使用Spring AOP+註解基於CAS方式實現java的樂觀鎖)。此時,如果,客戶A和客戶B同時讀取到庫存剩餘100,在更新的時候,有一個操作會失敗。流程如下:
如何在直播平臺開發中,防止商品庫存扣除時超賣?
該種方式可以大大提高併發性,也可以保證直播平臺開發資料的一致性;通過重試次數和重試時間的條件控制,可以防止過多的重試帶來的資料庫壓力。

可以使用直接遞減的方式執行麼?

在抵扣庫存的時候,有的人提議不執行select,計算,set三段式的操作,直接扣減的方式,並且對於扣減到小於零的情況作了判斷。虛擬碼如下:
update stock_table set remaing_stock=remaing_stock-${quantity} 
where id =商品id
and remaing_stock>${quantity};
在直播平臺開發的分散式服務呼叫中,因為網路異常,獲取伺服器異常,可能在微服務呼叫時,存在服務重試。例如,場景的閘道器超時,服務重試機制。此時,該種方式不滿足冪等性,而存在多扣的情況。例如,同一使用者扣減庫存時,服務重試,極端情況下,該使用者扣減庫存操作執行多次,則就出現了商品超賣。

可以使用redis進行庫存的抵扣麼?

由於沒有研究過redis原始碼,對於這種方式參考了大牛的回覆,答案是可以在直播平臺開發中使用redis的事務性扣減餘額,但在CAS機制上比mysql沒有優勢,高效能是因為其記憶體儲存的原因,帶來的副作用是資料有丟失風險。
本文轉載自網路,轉載僅為分享乾貨知識,如有侵權歡迎聯絡雲豹科技進行刪除處理 原文連結:https://blog.csdn.net/new_com/article/details/105568124


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69996194/viewspace-2848913/,如需轉載,請註明出處,否則將追究法律責任。

相關文章