分布式鎖 3 分布式鎖租約續期

2022-05-04 21:18:11 字數 2363 閱讀 8436

redis分布式鎖在加鎖的時候,我們一般都會給乙個鎖的過期時間(ttl),這是為了防止加鎖後client宕機,鎖無法被釋放的問題。但是所有這種姿勢的用法都會面臨同乙個問題,就是沒發保證client的執行時間一定小於鎖的ttl。雖然大多數程式設計師都會樂觀的認為這種情況不可能發生,但是各種異常情況都會導致該問題的發生,比如網路延遲,jvm full gc。

martin kleppmann也質疑過這一點,這裡直接用他的圖:

client1獲取到鎖

client1開始任務,然後發生了stw的gc,時間超過了鎖的過期時間

client2 獲取到鎖,開始了任務

client1的gc結束,繼續任務,這個時候client1和client2都認為自己獲取了鎖,都會處理任務,從而發生錯誤。

如何解決呢?

可以給鎖設定乙個watchdog自動給鎖進行續期。實現的原理就是在加鎖成功之後啟動乙個定時執行緒(watchdog)自動給鎖進行續期。

// org.redisson.redissonlock#tryacquireasync()

private rfuturetryacquireasync(long leasetime, timeunit unit, long threadid)

rfuturettlremainingfuture = trylockinnerasync(

commandexecutor.getconnectionmanager().getcfg().getlockwatchdogtimeout(),

timeunit.milliseconds, threadid, rediscommands.eval_long);

// 非同步獲取結果,如果獲取鎖成功,則啟動定時執行緒進行鎖續約

ttlremainingfuture.oncomplete((ttlremaining, e) ->

// lock acquired

if (ttlremaining == null)

});return ttlremainingfuture;

}

// org.redisson.redissonlock#scheduleexpirationrenewal()

private static final concurrentmapexpiration_renewal_map =

new concurrenthashmap<>();

private void scheduleexpirationrenewal(long threadid) else

}

// org.redisson.redissonlock#renewexpiration()

private void renewexpiration()

timeout task = commandexecutor.getconnectionmanager().newtimeout(new timertask()

long threadid = ent.getfirstthreadid();

if (threadid == null)

// renewexpirationasync續約租期

rfuturefuture = renewexpirationasync(threadid);

future.oncomplete((res, e) ->

if (res)

});}

//每次間隔租期的1/3時間執行

}, internallockleasetime / 3, timeunit.milliseconds);

ee.settimeout(task);

}

// org.redisson.redissonlock#renewexpirationasync()

protected rfuturerenewexpirationasync(long threadid)

watchdog其實就是乙個週期任務,給出乙個更加簡單的例子:

private void startwatchdog(string lockname, string lockvalue, int expiredtime)  else 

}))).start();

}public class schedulelockwatchdogtask implements scheduletask

@override

public void executetask()

}

分布式 分布式鎖

本質是利用redis的setnx 方法的特性來加鎖,setnx 即key不存在則設定key,否則直接返回false,要求在分布式系統中使用同乙個redis服務,以下提供兩種解決方案 1 直接使用redistemplate 這其實並不能完全保證高併發下的安全問題,因為可能在鎖過期之後該執行緒尚未執行完...

分布式專題 分布式鎖

在傳統的單體應用架構中,遇到併發安全性問題時我們可以通過同步鎖synchronized,同步 塊,reentrantlock等方式都可以解決,但隨著業務的發展,單體應用架構不能滿足龐大的使用者請求量,於是分布式系統應用而生,在分布式系統中,由於每個系統都執行在不同的伺服器上,有著不同的jvm,所以j...

zookeeper(3)分布式鎖

在乙個分布式系統中,如何保證乙個操作,同一時間只有乙個執行緒可以執行,這就是分布式鎖的使用場景,同一時間,只有乙個執行緒可以獲得鎖的使用權。實現乙個分布式鎖,可以有以下3種方法。1 在mysql中,使用悲觀鎖 select from t where id for update 可以對行資料進行加鎖,...