欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

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

一、分布式鎖的核心要求

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

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

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

SET lock:order:12345 "client_1" NX EX 10
  • NX:key 不存在時(shí)才設(shè)置(保證互斥)
  • EX 10:10秒后自動(dòng)過期(防死鎖)
  • client_1:唯一客戶端標(biāo)識(shí)(用于釋放時(shí)校驗(yàn))

? 問題:無續(xù)期機(jī)制,業(yè)務(wù)執(zhí)行超時(shí)會(huì)自動(dòng)釋放,導(dǎo)致并發(fā)。

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

直接 DEL 鎖可能誤刪其他客戶端的鎖。應(yīng)使用 Lua 腳本校驗(yàn) 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;
}

四、自動(dòng)續(xù)期(Watchdog 機(jī)制)

如果業(yè)務(wù)執(zhí)行時(shí)間超過鎖過期時(shí)間,鎖會(huì)被自動(dòng)釋放,導(dǎo)致多個(gè)客戶端同時(shí)進(jìn)入臨界區(qū)。

解決方案:啟動(dòng)一個(gè)后臺(tái)線程(Watchdog),每隔一段時(shí)間檢查鎖是否仍被持有,若持有則延長過期時(shí)間。

Watchdog 工作流程:

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

五、完整實(shí)現(xiàn)方案對(duì)比

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

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

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

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

1. 添加依賴

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

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

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

3. Redisson 的 Watchdog 原理

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

? 無需擔(dān)心業(yè)務(wù)超時(shí),只要客戶端存活,鎖就不會(huì)被釋放。

七、原生 Redis + Lua 實(shí)現(xiàn)(學(xué)習(xí)用)

如果你不想使用 Redisson,也可自行實(shí)現(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. 啟動(dòng) 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) {
            // 只有當(dāng)前客戶端持有鎖時(shí)才續(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 腳本實(shí)現(xiàn)。

4. 使用示例

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

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

可重入鎖需記錄:

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

可用 Hash 結(jié)構(gòu)實(shí)現(xiàn):

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

加鎖時(shí):

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

釋放時(shí):

  • value -1,為 0 時(shí)刪除 key

九、最佳實(shí)踐與注意事項(xiàng)

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

十、常見問題(FAQ)

Q1:Redis 主從切換會(huì)導(dǎo)致鎖失效嗎?

? 會(huì)!主節(jié)點(diǎn)加鎖后未同步到從節(jié)點(diǎn),主節(jié)點(diǎn)宕機(jī),從節(jié)點(diǎn)升主,鎖丟失。

解決方案

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

Q2:Watchdog 占用資源嗎?

? 占用少量 CPU 和連接,但可接受。Redisson 默認(rèn)只在持有鎖時(shí)啟動(dòng)。

Q3:能用 SETNX + DEL 嗎?

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

十一、總結(jié):Redis 分布式鎖實(shí)現(xiàn)方案對(duì)比

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

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

?? 核心代碼一句話:

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

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

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

相關(guān)文章

  • Redis不同數(shù)據(jù)類型使用場(chǎng)景代碼實(shí)例

    Redis不同數(shù)據(jù)類型使用場(chǎng)景代碼實(shí)例

    這篇文章主要介紹了Redis不同數(shù)據(jù)類型使用場(chǎng)景代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Redis持久化機(jī)制之RDB與AOF的使用

    Redis持久化機(jī)制之RDB與AOF的使用

    這篇文章主要介紹了Redis持久化機(jī)制之RDB與AOF的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • Redis 實(shí)現(xiàn)隊(duì)列原理的實(shí)例詳解

    Redis 實(shí)現(xiàn)隊(duì)列原理的實(shí)例詳解

    這篇文章主要介紹了Redis 實(shí)現(xiàn)隊(duì)列原理的實(shí)例詳解的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • Redis整合Lua腳本的實(shí)現(xiàn)操作

    Redis整合Lua腳本的實(shí)現(xiàn)操作

    Redis對(duì)lua腳本的支持是從Redis2.6.0版本開始引入的,它可以讓用戶在Redis服務(wù)器內(nèi)置的Lua解釋器中執(zhí)行指定的lua腳本,本文就來介紹一下Redis整合Lua腳本的實(shí)現(xiàn),感興趣的可以了解一下
    2024-03-03
  • Redis中跳表的實(shí)現(xiàn)原理分析

    Redis中跳表的實(shí)現(xiàn)原理分析

    Redis中的跳表是一種高效的多層鏈表結(jié)構(gòu),通過隨機(jī)概率算法決定節(jié)點(diǎn)的層數(shù),從而實(shí)現(xiàn)快速的插入、刪除和查詢操作,跳表的平均時(shí)間復(fù)雜度為O(logn),最差情況為O(n),每個(gè)節(jié)點(diǎn)包含值和指向更高層節(jié)點(diǎn)的指針,以及回退指針以提高操作效率
    2025-02-02
  • Redis配置外網(wǎng)可訪問(redis遠(yuǎn)程連接不上)的方法

    Redis配置外網(wǎng)可訪問(redis遠(yuǎn)程連接不上)的方法

    默認(rèn)情況下,當(dāng)我們?cè)诓渴鹆藃edis服務(wù)之后,redis本身默認(rèn)只允許本地訪問。Redis服務(wù)端只允許它所在服務(wù)器上的客戶端訪問,如果Redis服務(wù)端和Redis客戶端不在同一個(gè)機(jī)器上,就要進(jìn)行配置。
    2022-12-12
  • Redis與緩存解讀

    Redis與緩存解讀

    文章介紹了Redis作為緩存層的優(yōu)勢(shì)和缺點(diǎn),并分析了六種緩存更新策略,包括超時(shí)剔除、先刪緩存再更新數(shù)據(jù)庫、旁路緩存、先更新數(shù)據(jù)庫再刪緩存、先更新數(shù)據(jù)庫再更新緩存、讀寫穿透和異步緩存寫入模式,還討論了緩存常見問題
    2025-01-01
  • Redis超詳細(xì)分析分布式鎖

    Redis超詳細(xì)分析分布式鎖

    在單體應(yīng)用中,如果我們對(duì)共享數(shù)據(jù)不進(jìn)行加鎖操作,會(huì)出現(xiàn)數(shù)據(jù)一致性問題,我們的解決辦法通常是加鎖。下面我們一起聊聊使用redis來實(shí)現(xiàn)分布式鎖
    2022-07-07
  • Redis分布式鎖的實(shí)現(xiàn)方式

    Redis分布式鎖的實(shí)現(xiàn)方式

    本文主要介紹了Redis分布式鎖的實(shí)現(xiàn)方式,分布式鎖是?滿足分布式系統(tǒng)或集群模式下多進(jìn)程可見并且互斥的鎖。感興趣的同學(xué)可以參考閱讀
    2023-04-04
  • redis 億級(jí)數(shù)據(jù)讀取的實(shí)現(xiàn)

    redis 億級(jí)數(shù)據(jù)讀取的實(shí)現(xiàn)

    本文主要介紹了redis 億級(jí)數(shù)據(jù)讀取的實(shí)現(xiàn),億級(jí)數(shù)據(jù)規(guī)模下實(shí)現(xiàn)高效的數(shù)據(jù)讀取成為了許多企業(yè)和開發(fā)者面臨的重大挑戰(zhàn),下面就來介紹一下,感興趣的可以了解一下
    2024-08-08

最新評(píng)論