91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

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

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

濉溪县| 萨迦县| 舟山市| 雷州市| 新源县| 凤凰县| 张家港市| 凉城县| 邯郸市| 民丰县| 三亚市| 临潭县| 日照市| 丰台区| 莱西市| 柳林县| 新宁县| 张掖市| 铁岭市| 合江县| 称多县| 兴城市| 土默特右旗| 济南市| 天全县| 彝良县| 开江县| 晋宁县| 汨罗市| 株洲县| 东乡县| 安图县| 盐山县| 城口县| 宣恩县| 土默特左旗| 五原县| 当阳市| 五寨县| 赤壁市| 瓦房店市|