Redisson 看門狗(Watch Dog)機制實現原理
Redisson 的?Watch Dog?機制是分布式鎖的核心組件之一,用于?自動續期?鎖的過期時間,防止業務邏輯執行時間超過鎖的持有時間,導致鎖提前釋放而引發并發問題。以下是其實現原理的詳細分析:
1. 看門狗的核心作用
-
問題背景:
當線程獲取鎖后,如果業務執行時間超過鎖的過期時間(如設置的?leaseTime=30s
),鎖可能會被其他線程獲取,導致數據不一致。 -
解決方案:
Watch Dog 會?定期檢查?并?自動延長鎖的過期時間,確保業務執行完成前鎖不會失效。
2. 看門狗的工作流程
(1)加鎖時啟動看門狗
當使用?tryLock()
?或?lock()
?方法獲取鎖時:
-
如果?不指定?
leaseTime
(即鎖無固定過期時間),Redisson 會?自動啟動 Watch Dog。 -
如果?指定?
leaseTime
(如?lock.lock(10, TimeUnit.SECONDS)
),則?不會啟動 Watch Dog(由業務自行控制鎖的釋放)。
關鍵代碼(RedissonLock.class)
java
復制
下載
// 如果未指定 leaseTime,則啟動 Watch Dog if (leaseTime == -1) {// 設置默認過期時間(30秒)internalLockLeaseTime = lockWatchdogTimeout;// 啟動 Watch DogscheduleExpirationRenewal(threadId); }
(2)Watch Dog 的續期邏輯
Watch Dog 本質上是一個?后臺定時任務,默認每?10 秒?檢查一次鎖的狀態,并重置鎖的過期時間(續期至 30 秒)。
續期任務(renewExpiration()
)
java
復制
下載
protected void renewExpiration() {// 1. 獲取當前線程的鎖信息ExpirationEntry entry = EXPIRATION_RENEWAL_MAP.get(getEntryName());if (entry == null) {return;}// 2. 創建定時任務,每 10 秒執行一次Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {@Overridepublic void run(Timeout timeout) {// 3. 檢查鎖是否仍被當前線程持有if (EXPIRATION_RENEWAL_MAP.containsKey(getEntryName())) {// 4. 執行 Lua 腳本,延長鎖的過期時間RFuture<Boolean> future = renewExpirationAsync(threadId);future.onComplete((res, e) -> {if (e != null) {log.error("Can't update lock expiration", e);return;}if (res) {// 5. 遞歸調用,繼續續期renewExpiration();}});}}}, lockWatchdogTimeout / 3, TimeUnit.MILLISECONDS); // 默認 10 秒(30s / 3)entry.setTimeout(task); }
Lua 續期腳本
lua
復制
下載
-- KEYS[1]: 鎖的 Key -- ARGV[1]: 過期時間(30s) -- ARGV[2]: 客戶端唯一標識(UUID + 線程ID)-- 1. 檢查鎖是否仍由當前線程持有 if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then-- 2. 延長鎖的過期時間redis.call('pexpire', KEYS[1], ARGV[1]);return 1; end; return 0;
(3)釋放鎖時關閉 Watch Dog
當調用?unlock()
?時,Redisson 會?清理 Watch Dog 任務,避免不必要的續期。
關鍵代碼
java
復制
下載
@Override public void unlock() {try {// 1. 釋放鎖get(unlockAsync(Thread.currentThread().getId()));} finally {// 2. 取消 Watch Dog 任務cancelExpirationRenewal(Thread.currentThread().getId());} }
3. 關鍵配置參數
參數 | 默認值 | 說明 |
---|---|---|
lockWatchdogTimeout | 30,000 ms | 鎖的默認過期時間(未指定?leaseTime ?時生效) |
續期間隔 | 10,000 ms | Watch Dog 的檢查間隔(lockWatchdogTimeout / 3 ) |
leaseTime | -1 | 如果手動指定(如?lock.lock(10, TimeUnit.SECONDS) ),則?不啟動 Watch Dog |
4. 看門狗的適用場景
(1)適合使用 Watch Dog 的情況
-
業務執行時間不確定(如網絡請求、復雜計算)。
-
需要防止鎖意外過期(如 GC 停頓導致業務阻塞)。
(2)不適合使用 Watch Dog 的情況
-
能明確預估業務時間(如?
leaseTime=10s
,業務肯定在 5s 內完成)。 -
對鎖的持有時間敏感(如嚴格要求鎖 10s 后必須釋放)。
5. 與其他方案的對比
機制 | Redisson Watch Dog | SETEX + 自旋重試 | Zookeeper 臨時節點 |
---|---|---|---|
自動續期 | ? 后臺線程定時續期 | ? 需業務代碼控制 | ? 依賴 Session 超時 |
鎖安全性 | 高(Lua 腳本原子操作) | 中(依賴業務代碼正確性) | 高(CP 系統保證) |
適用場景 | 高并發、業務時間不確定 | 簡單場景、短任務 | 強一致性要求嚴格的場景 |
6. 最佳實踐
-
推薦使用默認 Watch Dog(不指定?
leaseTime
),避免鎖提前釋放。 -
避免濫用鎖:鎖的粒度要小(如?
lock:order:1001
?而非?lock:order
)。 -
監控 Watch Dog:如果發現續期失敗,可能是 Redis 連接問題或鎖被強制刪除。
總結
Redisson 的?Watch Dog 機制?通過?后臺定時任務 + Lua 腳本續期,解決了分布式鎖在長業務場景下的?自動保活問題,是生產環境高可用分布式鎖的核心保障。
開啟新對話