alibaba工程師,如何解決樂觀鎖沖突問題?


很多做過電商系統的人應該知道,我們在設計電商系統中關於商品庫存扣減時,在大部分情況下(並發量不高時),商品庫存都可以直接在關系型數據庫中進行扣減,那么在限時搶購活動正式開始后,那些單價比平時更給力、更具吸引力的熱賣商品大家肯定都會積極踴躍地參與搶購,這必然會產生大量針對數據庫同一行記錄的並發更新操作。因此數據庫為了保證原子’性, InnoDB 引擎默認會對同一行數據記錄加鎖,把前端的並發請求變成串行操作,以確保數據更新時的正確性。
 
如果直接在數據庫中扣減庫存,應該如何避免商品超賣呢?
 
在生產環境中我們可以通過樂觀鎖機制來避免這個問題。所謂樂觀鎖,簡單來說,就是在 item表中建立一個 version 字段。假設某一個熱賣商品的實際庫存為n,出於對性能的考慮,查詢庫存操作是不建議加 for update (悲觀鎖,代價太大)的,那么在並發場景下,必然會導致多個用戶拿到的 stock 和 version都一樣。因此當第1個用戶成功扣減商品庫存后, 需要將 item表中的 version加1, 當第 2個用戶扣減庫存時,由於 version 不匹配,那么無法扣減成功,並且會拋出:StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)的異常。
 
當然,對於樂觀鎖一般的做法,是較為友好的提醒用戶:“數據已經被其他人更改,請重新操作!”。可能一般系統這種方式可行,但是對於高並發的電商系統來講,這就非常不友好,甚至直接導致客戶大面積流失,那么有沒有相對較為好的解決方案呢?
 
實際上,我們可以這樣干
 
為了提升庫存扣減的成功率,可以適當進行重試,如果庫存不足,則說明商品已經售罄,反之扣減庫存后 version 繼續加1 。關於在數據庫中使用樂觀鎖扣減庫存的偽代碼,如下所示:

 

除了使用樂觀鎖,還可以在扣減商品庫存時,利用 “實際庫存數 大於 扣減庫存數” 作為條件來替代 version 匹配,防止商品超賣。相對於樂觀鎖,采用這種方式會更加
直接,由於充分利用了 InnoDB 引擎提供的行鎖特性,因此大大提升和保障了庫存扣減的成功率,如下所示:
 
/* 實際庫存數 大於 扣減庫存數*/
UPDATE item SET stock=stock -  扣減庫存數 WHERE item id=l AND stock >=  扣減庫存數
 
兩種方案均能夠有效避免商品超賣,當然還是推薦使用樂觀鎖的使用方案。
 
 
 
 


免責聲明!

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



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