[分享]淺談電商庫存模型

本文討論內容不包含秒殺,僅僅是最普遍的庫存模型而已,重點討論如何避免超賣少賣


1、 基本概念

1.1 超賣

實際庫存已經爲0,但是依舊賣出去了。可能導致商家無貨可發。

1.2 少賣

明明有貨,但是庫存被鎖定,導致商家貨賣不出去。


2、 分佈式事務簡述

2.1 消息事務+最終一致性

所謂的消息事務就是基於消息中間件的兩階段提交,本質上是對消息中間件的一種特殊利用,
它是將本地事務和發消息放在了一個分佈式事務裏,保證要麼本地操作成功成功並且對外發消息成功,
要麼兩者都失敗,開源的RocketMQ就支持這一特性,具體原理如下:

圖 fenzu

  • 1、A系統向消息中間件發送一條預備消息
  • 2、消息中間件保存預備消息並返回成功
  • 3、A執行本地事務
  • 4、A發送提交消息給消息中間件

通過以上4步完成了一個消息事務。對於以上的4個步驟,每個步驟都可能產生錯誤,下面一一分析:

  • 步驟一出錯,則整個事務失敗,不會執行A的本地操作
  • 步驟二出錯,則整個事務失敗,不會執行A的本地操作
  • 步驟三出錯,這時候需要回滾預備消息,怎麼回滾?答案是A系統實現一個消息中間件的回調接口,消息中間件會去不斷執行回調接口,檢查A事務執行是否執行成功,如果失敗則回滾預備消息
  • 步驟四出錯,這時候A的本地事務是成功的,那麼消息中間件要回滾A嗎?答案是不需要,其實通過回調接口,消息中間件能夠檢查到A執行成功了,這時候其實不需要A發提交消息了,消息中間件可以自己對消息進行提交,從而完成整個消息事務

2.2 TCC編程模式

所謂的TCC編程模式,也是兩階段提交的一個變種。TCC提供了一個編程框架,將整個業務邏輯分爲三塊:Try、Confirm和Cancel三個操作。
以在線下單爲例,Try階段會去扣庫存,Confirm階段則是去更新訂單狀態,如果更新訂單失敗,則進入Cancel階段,會去恢復庫存。
總之,TCC就是通過代碼人爲實現了兩階段提交,不同的業務場景所寫的代碼都不一樣,複雜度也不一樣,因此,這種模式並不能很好地被複用。


3、 庫存模型

  • 1.下單的時候每個訂單都會有預佔庫存。
  • 2.訂單出庫或取消解鎖預佔。
  • 3.可售庫存 = 現貨庫存 - 預佔庫存

具體下單操作流程是

下單 –> 預佔(預佔庫存+1) –> 支付 –> 出庫(釋放預佔並減庫存,涉及到分佈式事務) –> 完成

重點討論此方案的意義,跟出庫部分。

3.1 爲什麼設計成預佔庫存?

以下均爲個人理解

  • 1.庫存和下單分離,下單了不會實際減少庫存。真正的實物庫存跟邏輯庫存分離,方便(盤庫、補貨等)僅僅用實物庫存的場景跟高併發的場景(下單)分離。
  • 2.預佔可以減少庫存表的操作頻率,減庫存可以在發貨的時候統一處理。(操作多次預佔表後僅在必要時操作一次庫存表,跟1有共通之處)

3.2 預佔庫存怎麼加?

  • 1.可以用mysql樂觀鎖(version遞增避免aba)
  • 2.可以用redis watch(同樣基於cas,無aba)

3.3 出庫部分怎麼保證事務?

  • 1.先出庫還是先釋放預佔?

    爲了避免超賣選擇先減庫存,再釋放預佔。

  • 2.如何保證事務一致性?

    採用消息機制的2pc保證分佈式事務。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章