電商中的庫存管理實現-mysql與redis


 

庫存是電商系統的核心環節,如何做到不少賣,不超賣是庫存關心的核心業務問題。業務量大時帶來的問題是如何更快速的處理庫存計算。 
此處以最簡模式來討論庫存設計。 
以下內容只做分析,不能直接套用,歡迎各位同道前來交流指正 
庫存模型:sku,num。 
sku是標示商品的唯一編號,num是商品的數量。 
訂單處理時需扣減商品庫存。 

mysql實現

 

庫存初始數據: 
庫存表 
mysql隔離級別READ-COMMITTED 
扣減1001庫存7:

10-7=3; 
3>0; 
開始扣減庫存 
UPDATE stock SET num=3 WHERE sku=1001; 
在串行執行情況下以上邏輯是正確的處理方式。 
如果是並發執行,可能會出現這種情況: 
10-7=3; 
庫存在另外一個線程中被修改為5 
UPDATE stock SET num=3 WHERE sku=1001; 
庫存最終被修改為3

一共賣出5+7=12個商品,實際總商品數是10,超賣發生。 
為解決超賣引入如下方案:

10-7=3; 
3>0; 
開始扣減庫存 
庫存在另外一個線程中被修改為5 
UPDATE stock SET num=num-7 WHERE num>=7 AND sku=1001; 
update失敗,超賣解決。

考慮到訂單的商品有多個,那在並發執行的情況下是否還是正常呢? 
現有訂單1,訂單2同時處理,都是1001扣減庫存5,1002扣減庫存10 
訂單1:

UPDATE stock SET num=num-5 WHERE num>=5 AND sku=1001; 
UPDATE stock SET num=num-10 WHERE num>=10 AND sku=1002;

訂單2:

UPDATE stock SET num=num-10 WHERE num>=10 AND sku=1002; 
UPDATE stock SET num=num-5 WHERE num>=5 AND sku=1001;

若sql執行情況是訂單1先修改1001,訂單2修改1002,這個時候產生死鎖,有一個訂單必然會失敗。 
少賣發生。 
如果是訂單2中第二個商品是1003會怎么樣呢? 
兩個訂單的庫存修改會變成串行執行。 
這種情況下會帶來性能下降的問題,事務超時的時候會發生多個訂單失敗的情況。 
多個訂單失敗后如果訂單依然要處理,此時庫存沒有扣減,又會發生超賣。

結論:mysql可以保證數據一致性和持久性,但是性能不高,在量級較高的情況下庫存並沒有控制好少賣超賣的情況。

 

redis實現

 

mysql的缺點是如此顯而易見,為了解決這個問題,現在引入redis。 
redis的讀寫速度快,數據操作都在內存中運行,性能必然比mysql高。 
string類型提供了decrby方法,可以以原子方式對string做減法。 
對1001庫存減5:

decrby 1001 5 
獲得返回值,如果小於0則執行 
incrby 1001 5 
並且所有相關數據回滾 
在多線程環境中會有多個訂單同時回滾,庫存充足的情況。產生這種現象后,失敗的訂單可以留待下次再行處理。

但是庫存的值並不能用來做實時計算,因為失敗訂單的庫存沒有進行計算。 
redis沒有事務,無法保證數據一致性。 
結論:redis解決了性能問題,但是數據一致性無法保證。

 

其它

 

為解決mysql問題,可以結合異步定時扣減庫存,隊列做。

最后,不管用mysql還是redis 都各有優缺點.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM