最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何使用Redis 實現(xiàn)分布式鎖(含自動續(xù)期與安全釋放)

 更新時間:2025年08月12日 09:32:21   作者:csdn_tom_168  
本文詳解用Redis實現(xiàn)分布式鎖,包含自動續(xù)期與安全釋放,推薦使用Redisson,內(nèi)置可重入、Watchdog及高可用支持,對比原生和自研方案,強調(diào)其在生產(chǎn)環(huán)境的高效與安全性,感興趣的朋友跟隨小編一起看看吧

用 Redis 實現(xiàn)分布式鎖(含自動續(xù)期與安全釋放)詳解

在分布式系統(tǒng)中,多個服務實例可能同時操作共享資源(如庫存扣減、訂單生成),為保證數(shù)據(jù)一致性,必須使用 分布式鎖。Redis 憑借其高性能和原子操作能力,成為實現(xiàn)分布式鎖的常用選擇。

本文將深入講解如何用 Redis 實現(xiàn)一個 安全、可重入、帶自動續(xù)期(Watchdog)、支持高可用 的分布式鎖,并提供 Java 實現(xiàn)示例(含 Redisson 與原生 Lua 腳本兩種方式)。

一、分布式鎖的核心要求

要求說明
? 互斥性同一時間只有一個客戶端能持有鎖
? 可重入性同一線程可多次獲取同一把鎖
? 鎖釋放安全只能由加鎖的客戶端釋放(防誤刪)
? 自動續(xù)期(Watchdog)防止業(yè)務執(zhí)行時間超過鎖過期時間
? 高可用支持主從、集群、哨兵模式
? 高性能加鎖/釋放速度快,不影響業(yè)務

二、基礎實現(xiàn):SET + NX + EX

最簡單的分布式鎖實現(xiàn):

SET lock:order:12345 "client_1" NX EX 10
  • NX:key 不存在時才設置(保證互斥)
  • EX 10:10秒后自動過期(防死鎖)
  • client_1:唯一客戶端標識(用于釋放時校驗)

? 問題:無續(xù)期機制,業(yè)務執(zhí)行超時會自動釋放,導致并發(fā)。

三、安全釋放鎖:Lua 腳本防誤刪

直接 DEL 鎖可能誤刪其他客戶端的鎖。應使用 Lua 腳本校驗 value

? Lua 腳本(unlock.lua)

-- KEYS[1] = lock key
-- ARGV[1] = client_id
if redis.call('get', KEYS[1]) == ARGV[1] then
    return redis.call('del', KEYS[1])
else
    return 0
end

Java 調(diào)用示例:

public boolean unlock(String lockKey, String clientId) {
    String script = 
        "if redis.call('get', KEYS[1]) == ARGV[1] then " +
        "   return redis.call('del', KEYS[1]) " +
        " else " +
        "   return 0 " +
        " end";
    DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
    redisScript.setScriptText(script);
    redisScript.setResultType(Long.class);
    Long result = redisTemplate.execute(
        redisScript,
        Collections.singletonList(lockKey),
        clientId
    );
    return result != null && result == 1;
}

四、自動續(xù)期(Watchdog 機制)

如果業(yè)務執(zhí)行時間超過鎖過期時間,鎖會被自動釋放,導致多個客戶端同時進入臨界區(qū)。

解決方案:啟動一個后臺線程(Watchdog),每隔一段時間檢查鎖是否仍被持有,若持有則延長過期時間。

Watchdog 工作流程:

客戶端A加鎖(EX 30s)
     ↓
啟動 Watchdog 線程(每10s檢查一次)
     ↓
若鎖仍存在且屬于本客戶端 → 執(zhí)行 EXPIRE lock:xxx 30
     ↓
業(yè)務執(zhí)行完成 → 取消續(xù)期 + 釋放鎖

五、完整實現(xiàn)方案對比

方案是否推薦說明
?? 原生 SET + Lua?? 基礎可用需自行實現(xiàn)續(xù)期、可重入
?? Redisson(推薦)? 強烈推薦內(nèi)置 Watchdog、可重入、公平鎖等
?? Jedis + 自研? 不推薦容易出錯,維護成本高

六、使用 Redisson 實現(xiàn)(推薦方案)

Redisson 提供了開箱即用的分布式鎖,完美支持:

  • 可重入
  • 自動續(xù)期(Watchdog)
  • 公平鎖、讀寫鎖
  • 高可用(集群/哨兵)

1. 添加依賴

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.24.1</version>
</dependency>

2. 獲取鎖并自動續(xù)期

@Autowired
private RedissonClient redissonClient;
public void doBusiness() {
    RLock lock = redissonClient.getLock("lock:order:12345");
    try {
        // 嘗試加鎖,最多等待10秒,上鎖后30秒自動解鎖
        boolean res = lock.tryLock(10, 30, TimeUnit.SECONDS);
        if (res) {
            try {
                // 執(zhí)行業(yè)務邏輯(可能耗時較長)
                System.out.println("Locked! Doing business...");
                Thread.sleep(25000); // 模擬長任務
            } finally {
                lock.unlock(); // 自動取消續(xù)期 + 安全釋放
            }
        } else {
            System.out.println("Failed to acquire lock");
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}

3. Redisson 的 Watchdog 原理

  • 默認鎖過期時間:30s
  • Watchdog 每 10s 檢查一次
  • 若客戶端仍持有鎖 → 自動 EXPIRE lock:xxx 30
  • 解鎖時自動取消續(xù)期

? 無需擔心業(yè)務超時,只要客戶端存活,鎖就不會被釋放。

七、原生 Redis + Lua 實現(xiàn)(學習用)

如果你不想使用 Redisson,也可自行實現(xiàn) Watchdog。

1. 加鎖(SETNX + EX)

public boolean tryLock(String lockKey, String clientId, int expireSeconds) {
    String result = redisTemplate.opsForValue()
        .setIfAbsent(lockKey, clientId, expireSeconds, TimeUnit.SECONDS);
    return Boolean.TRUE.equals(result);
}

2. 啟動 Watchdog 線程

private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private volatile boolean isLocked = false;
public void watchDog(String lockKey, String clientId, int expireSeconds) {
    isLocked = true;
    scheduler.scheduleAtFixedRate(() -> {
        if (isLocked) {
            // 只有當前客戶端持有鎖時才續(xù)期
            String current = redisTemplate.opsForValue().get(lockKey);
            if (clientId.equals(current)) {
                redisTemplate.expire(lockKey, expireSeconds, TimeUnit.SECONDS);
            }
        }
    }, expireSeconds / 3, expireSeconds / 3, TimeUnit.SECONDS);
}

3. 釋放鎖(Lua 腳本)

見前文 Lua 腳本實現(xiàn)。

4. 使用示例

String lockKey = "lock:order:12345";
String clientId = "client_" + Thread.currentThread().getId();
if (tryLock(lockKey, clientId, 30)) {
    try {
        watchDog(lockKey, clientId, 30); // 啟動續(xù)期
        // 執(zhí)行業(yè)務
    } finally {
        isLocked = false; // 停止續(xù)期
        unlock(lockKey, clientId); // 安全釋放
    }
}

八、可重入鎖實現(xiàn)思路

可重入鎖需記錄:

  • 當前持有線程
  • 重入次數(shù)

可用 Hash 結構實現(xiàn):

# 鎖結構
lock:order:12345
  field: client_1
  value: 2   # 重入次數(shù)

加鎖時:

  • 若 key 不存在 → 設置 client_1:1
  • 若 key 存在且 field == client_1 → value +1
  • 否則失敗

釋放時:

  • value -1,為 0 時刪除 key

九、最佳實踐與注意事項

項目建議
?? 安全釋放必須使用 Lua 腳本校驗 client_id
?? 鎖過期時間設置合理(如 10~30s),避免過長導致阻塞
?? 自動續(xù)期使用 Redisson 或自研 Watchdog
?? 可重入生產(chǎn)環(huán)境必須支持
?? 阻塞操作鎖內(nèi)避免網(wǎng)絡調(diào)用、sleep
?? 監(jiān)控記錄加鎖失敗、等待時間
?? 異常處理確保 finally 中釋放鎖
?? 高可用使用 Redis 集群或哨兵

十、常見問題(FAQ)

Q1:Redis 主從切換會導致鎖失效嗎?

? 會!主節(jié)點加鎖后未同步到從節(jié)點,主節(jié)點宕機,從節(jié)點升主,鎖丟失。

解決方案

  • 使用 Redlock 算法(多個獨立 Redis 實例)
  • 使用 ZooKeeperetcd 實現(xiàn)更安全的分布式鎖
  • 多數(shù)場景下,Redisson + 主從已足夠(犧牲 CAP 中的 CP)

Q2:Watchdog 占用資源嗎?

? 占用少量 CPU 和連接,但可接受。Redisson 默認只在持有鎖時啟動。

Q3:能用 SETNX + DEL 嗎?

? 不安全!DEL 可能誤刪其他客戶端的鎖。

十一、總結:Redis 分布式鎖實現(xiàn)方案對比

方案是否可重入自動續(xù)期安全釋放推薦度
SETNX + DEL????
SETNX + Lua???????
自研 Watchdog????????
Redisson????????

? 結語
使用 Redis 實現(xiàn)分布式鎖,強烈推薦使用 Redisson。它封裝了復雜的細節(jié)(可重入、續(xù)期、安全釋放),讓你像使用本地鎖一樣操作分布式鎖。

?? 核心代碼一句話:

RLock lock = redisson.getLock("myLock");
lock.tryLock(10, 30, TimeUnit.SECONDS);

簡單、安全、高效,是生產(chǎn)環(huán)境的最佳實踐。

到此這篇關于如何使用Redis 實現(xiàn)分布式鎖(含自動續(xù)期與安全釋放)的文章就介紹到這了,更多相關Redis分布式鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 基于Redis位圖實現(xiàn)系統(tǒng)用戶登錄統(tǒng)計

    基于Redis位圖實現(xiàn)系統(tǒng)用戶登錄統(tǒng)計

    這篇文章主要介紹了基于Redis位圖實現(xiàn)系統(tǒng)用戶登錄統(tǒng)計,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • Redis不同數(shù)據(jù)類型的命令語句詳解

    Redis不同數(shù)據(jù)類型的命令語句詳解

    這篇文章主要介紹了Redis不同數(shù)據(jù)類型的命令語句,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-10-10
  • 淺談一下Redis的數(shù)據(jù)結構

    淺談一下Redis的數(shù)據(jù)結構

    這篇文章主要介紹了淺談一下Redis的數(shù)據(jù)結構,簡單字符串結構被用于存儲redis的key對象和String類型的value對象,其中的free和len字段可以輕松的使得在該字符串被修改時判斷是否需要擴容,需要的朋友可以參考下
    2023-08-08
  • redis的五大數(shù)據(jù)類型應用場景分析

    redis的五大數(shù)據(jù)類型應用場景分析

    這篇文章主要介紹了redis的五大數(shù)據(jù)類型實現(xiàn)原理,本文給大家分享五大數(shù)據(jù)類型的應用場景分析,需要的朋友可以參考下
    2021-08-08
  • 關于Redis?bigkeys命令會阻塞問題的解決

    關于Redis?bigkeys命令會阻塞問題的解決

    這篇文章主要介紹了關于Redis?bigkeys命令會阻塞問題的解決,今天分享一次Redis引發(fā)的線上事故,避免再次踩雷,實現(xiàn)快速入門,需要的朋友可以參考下
    2023-03-03
  • redis列表類型_動力節(jié)點Java學院整理

    redis列表類型_動力節(jié)點Java學院整理

    這篇文章主要為大家詳細介紹了redis列表類型的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • 詳解redis集群的三種方式

    詳解redis集群的三種方式

    Redis三種集群方式分別是主從復制,哨兵模式,Cluster集群,這篇文章主要介紹了redis集群的三種方式,本文給大家介紹的非常詳細,需要的朋友可以參考下
    2022-07-07
  • Redis特殊數(shù)據(jù)類型Geospatial地理空間

    Redis特殊數(shù)據(jù)類型Geospatial地理空間

    這篇文章主要為大家介紹了Redis特殊數(shù)據(jù)類型Geospatial地理空間,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • Redis中的AOF原理及分析

    Redis中的AOF原理及分析

    Redis的AOF通過記錄所有寫操作命令實現(xiàn)持久化,支持always/everysec/no三種同步策略,重寫機制優(yōu)化文件體積,與RDB結合可平衡數(shù)據(jù)安全與恢復效率
    2025-09-09
  • Redis 中spark參數(shù)executor-cores引起的異常解決辦法

    Redis 中spark參數(shù)executor-cores引起的異常解決辦法

    這篇文章主要介紹了Redis 中spark參數(shù)executor-cores引起的異常解決辦法的相關資料,需要的朋友可以參考下
    2017-03-03

最新評論

淮南市| 常德市| 武穴市| 商城县| 十堰市| 阜宁县| 通许县| 辽阳县| 洞头县| 略阳县| 紫金县| 山西省| 盘山县| 肇州县| 昌都县| 济宁市| 盖州市| 鄂托克前旗| 西乌珠穆沁旗| 开平市| 盐山县| 房山区| 清苑县| 汽车| 沙湾县| 旌德县| 辽阳县| 石家庄市| 古丈县| 玛曲县| 女性| 宝清县| 冀州市| 五家渠市| 黄龙县| 吴忠市| 伊宁县| 年辖:市辖区| 保德县| 沙河市| 阳西县|