記一次秒殺重複搶單問題

背景描述:

系統給APP用戶(客戶經理)定時推送一批客戶資源數據,這批數據在不同的客戶經理登錄APP都能看見,然後點擊搶的按鈕,就可以獲取這個客戶了,這種場景類似於秒殺搶單,存在多人同時點擊按鈕搶人,所以伴隨着較高的併發操作。

問題描述:

這時候問題就出來了,同一個地區的客戶經理都可以看到相同的客戶,所以他們在搶通一個客戶的時候,就會出現同時搶中的情況。

背景設置:

線上環境mysql隔離級別配置是 提交讀,zk分佈式鎖超時時間爲10s,myql沒有設置唯一索引。

問題分析:

搶單更新庫存方法採用的是zk分佈式鎖,按理說不應該出現,兩個經理同時搶中的情況。分析代碼執行流程:

在這裏插入圖片描述

那麼可能存在的一種情況:A先獲取鎖邏輯執行完了會釋放鎖,但事務未提交,同時超時時間未到;因爲超時時間未到B仍在等待獲取鎖,等A一釋放B可以馬上獲取鎖,因爲A事務未提交,B仍然可以通過校驗,這樣最終撞車了,導致AB同時搶到了客戶。因爲沒有唯一索引,所以AB都可以更新數據。

還存在另一種可能:由於對zk分佈式鎖進行了一層封裝,所以zk工具類存在兩個超時時間,第一個是默認的zk鎖超時時間,第二個超時就是個保險,如果真的執行了半天還不釋放,就強制釋放掉,也不能一直站着坑。
這就可能存在問題,A先獲得鎖,等待第一個超時時間過了,B線程會拋異常,B線程會回滾。然後又等到了第二個超時時間過了,不管A執行是否完畢,A都會釋放鎖。這時候恰好C線程趁虛而入獲取了鎖,這樣會導致A和C同時搶中了客戶,這時候如果強制釋放鎖的時候,沒有中斷、回滾A線程執行邏輯,就會出現重複搶單問題。

解決方案:

1. 把查詢的方法和搶單的方法都分別提取去來,作爲兩個子方法,分別加了一個事務,通過事務保證唯一性。

2. zk鎖的超時時間設置爲0,即A先獲取鎖,則B不在等待,直接拋異常返回提示。

3. mysql最好添加唯一索引,作爲一層保障,讓髒數據寫不進去。

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