您好,登錄后才能下訂單哦!
這篇文章主要介紹了Redis分布式鎖一定要避開的兩個坑是什么的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Redis分布式鎖一定要避開的兩個坑是什么文章都會有所收獲,下面我們一起來看看吧。
分析以下代碼存在什么問題:
// 分布式鎖服務 public interface RedisLockService { // 獲取鎖 public boolean getLock(String key); // 釋放鎖 public boolean releaseLock(String key); } // 業務服務 public class BizService { @Resource private RedisLockService redisLockService; public void bizMethod(String bizId) { try { // 獲取鎖 if(redisLockService.getLock(bizId)) { // 業務重復校驗 if(!bizValidate(bizId)) { throw new BizException(ErrorBizCode.REPEATED); } // 執行業務 return doBusiness(); } // 獲取鎖失敗 throw new BizException(ErrorBizCode.GET_LOCK_ERROR); } finally { // 釋放鎖 redisLockService.releaseLock(bizId); } } }
上述代碼看似沒問題,實則隱藏大問題。問題在于釋放鎖時沒有校驗當前線程是否拿到鎖:
線程1和線程2同一時刻訪問業務方法
線程2獲取鎖成功,進行業務處理
線程1沒有獲取到鎖,但是釋放鎖成功
此時有線程3嘗試獲取鎖成功,但是線程2業務沒有處理完,所以線程3不會導致業務重復異常
最終導致線程2和線程3重復執行業務
解決方案是在確認獲取鎖成功后才允許釋放鎖:
public class BizService { @Resource private RedisLockService redisLockService; public void bizMethod(String bizId) { boolean getLockSuccess = false; try { // 嘗試獲取鎖 getLockSuccess = redisLockService.getLock(bizId); // 獲取鎖成功 if(getLockSuccess) { // 業務重復校驗 if(!bizValidate(bizId)) { throw new BizException(ErrorBizCode.REPEATED); } // 執行業務 return doBusiness(); } // 獲取鎖失敗 throw new BizException(ErrorBizCode.GET_LOCK_ERROR); } finally { // 獲取鎖成功才允許釋放鎖 if(getLockSuccess) { redisLockService.releaseLock(bizId); } } } }
第二個問題是Redis還存在內存清理機制,可能會導致分布式鎖失效。
(1) 定期刪除
Redis定時檢查哪些key已經過期,發現過期則刪除
(2) 惰性刪除
如果key非常多,定期刪除會非常消耗資源,所以引入惰性刪除策略
如果Redis訪問key時發現已經過期則直接刪除
當內存不足時Redis會選擇一些元素進行刪除:
no-enviction
禁止驅逐數據,新寫入操作會報錯
volatile-lru
從已設置過期時間的數據集選擇最近最少使用的數據淘汰
volatile-ttl
從已設置過期時間的數據集選擇將要過期的數據淘汰
volatile-random
從已設置過期時間的數據集選擇任意的數據淘汰
allkeys-lru
從數據集選擇最近最少使用的數據淘汰
allkeys-random
從數據集選擇任意的數據淘汰
至少存在兩種場景導致分布式鎖失效問題:
場景一:Redis內存不足進行內存回收,使用allkeys-lru
或者allkeys-random
回收策略導致鎖失效
場景二:線程獲取分布式鎖成功,但處理業務時間過長,此時鎖到期被定時清理,導致其它線程獲取鎖成功并重復執行業務
通用方案是在數據庫層保護,例如庫存扣減業務在數據庫層用樂觀鎖。
udpate goods set stock = stock - #{acquire} where sku_id = #{skuId} and stock - #{acquire} >= 0
關于“Redis分布式鎖一定要避開的兩個坑是什么”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“Redis分布式鎖一定要避開的兩個坑是什么”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。