中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Redis分布式鎖一定要避開的兩個坑是什么

發布時間:2023-04-18 17:08:05 來源:億速云 閱讀:128 作者:iii 欄目:開發技術

這篇文章主要介紹了Redis分布式鎖一定要避開的兩個坑是什么的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Redis分布式鎖一定要避開的兩個坑是什么文章都會有所收獲,下面我們一起來看看吧。

1 第一個坑:錯誤釋放鎖時機

1.1. 發現問題

分析以下代碼存在什么問題:

// 分布式鎖服務
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重復執行業務

1.2 解決問題

解決方案是在確認獲取鎖成功后才允許釋放鎖:

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);
            }
        }
    }
}

2 第二個坑:緩存失效問題

第二個問題是Redis還存在內存清理機制,可能會導致分布式鎖失效。

2.1 過期清理機制

(1) 定期刪除

Redis定時檢查哪些key已經過期,發現過期則刪除

(2) 惰性刪除

如果key非常多,定期刪除會非常消耗資源,所以引入惰性刪除策略

如果Redis訪問key時發現已經過期則直接刪除

2.2 內存回收機制

當內存不足時Redis會選擇一些元素進行刪除:

no-enviction

禁止驅逐數據,新寫入操作會報錯

volatile-lru

從已設置過期時間的數據集選擇最近最少使用的數據淘汰

volatile-ttl

從已設置過期時間的數據集選擇將要過期的數據淘汰

volatile-random

從已設置過期時間的數據集選擇任意的數據淘汰

allkeys-lru

從數據集選擇最近最少使用的數據淘汰

allkeys-random

從數據集選擇任意的數據淘汰

至少存在兩種場景導致分布式鎖失效問題:

  • 場景一:Redis內存不足進行內存回收,使用allkeys-lru或者allkeys-random回收策略導致鎖失效

  • 場景二:線程獲取分布式鎖成功,但處理業務時間過長,此時鎖到期被定時清理,導致其它線程獲取鎖成功并重復執行業務

2.3 樂觀鎖

通用方案是在數據庫層保護,例如庫存扣減業務在數據庫層用樂觀鎖。

udpate goods set stock = stock - #{acquire} 
where sku_id = #{skuId} and stock - #{acquire} >= 0

關于“Redis分布式鎖一定要避開的兩個坑是什么”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“Redis分布式鎖一定要避開的兩個坑是什么”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

庐江县| 徐州市| 资中县| 亚东县| 宣化县| 苏州市| 娄烦县| 安福县| 莱芜市| 芦山县| 都江堰市| 襄城县| 土默特右旗| 清河县| 靖宇县| 育儿| 沂源县| 高邑县| 岑巩县| 太康县| 申扎县| 梅河口市| 浪卡子县| 饶平县| 拜城县| 福建省| 隆安县| 平果县| 洛川县| 油尖旺区| 丽水市| 龙南县| 同心县| 元阳县| 南宫市| 长阳| 彭山县| 信宜市| 汝城县| 上饶市| 宿州市|