您好,登錄后才能下訂單哦!
小編給大家分享一下怎么使用redis實現分布式鎖,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
最簡單的方法是使用setnx命令。key是鎖的唯一標識,按業務來決定命名。比如想要給一種商品的秒殺活動加鎖,可以給key命名為 “lock_hot_商品ID” 。而value設置成什么呢?我們可以姑且設置成1。加鎖的偽代碼如下:
setnx(key,1)
當一個線程執行setnx返回1,說明key原本不存在,該線程成功得到了鎖;當一個線程執行setnx返回0,說明key已經存在,該線程搶鎖失敗。
有加鎖就得有解鎖。當得到鎖的線程執行完任務,需要釋放鎖,以便其他線程可以進入。釋放鎖的最簡單方式是執行del指令,偽代碼如下:
del(key)
釋放鎖之后,其他線程就可以繼續執行setnx命令來獲得鎖。
鎖超時是什么意思呢?如果一個得到鎖的線程在執行任務的過程中掛掉,來不及顯式地釋放鎖,這塊資源將會永遠被鎖住,別的線程再也別想進來。
所以,setnx的key必須設置一個超時時間,以保證即使沒有被顯式釋放,這把鎖也要在一定時間后自動釋放。setnx不支持超時參數,所以需要額外的指令,
偽代碼如下:
expire(key, 30)
我們分布式鎖實現的第一版偽代碼如下:
if(setnx(key,1) == 1){ expire(key,30) try { do something ...... } finally { del(key) } }
上面的偽代碼中,存在著三個致命問題:
設想一個極端場景,當某線程執行setnx,成功得到了鎖:
setnx剛執行成功,還未來得及執行expire指令,節點1 Duang的一聲掛掉了。
這樣一來,這把鎖就沒有設置過期時間,變得“長生不老”,別的線程再也無法獲得鎖了。
怎么解決呢?setnx指令本身是不支持傳入超時時間的,但是Redis 2.6.12以上版本為set指令增加了可選參數,偽代碼如下:
set(key,1,30,NX)
這樣就可以取代setnx指令。
又是一個極端場景,假如某線程成功得到了鎖,并且設置的超時時間是30秒。
如果某些原因導致線程A執行的很慢很慢,過了30秒都沒執行完,這時候鎖過期自動釋放,線程B得到了鎖。
隨后,線程A執行完了任務,線程A接著執行del指令來釋放鎖。但這時候線程B還沒執行完,線程A實際上刪除的是線程B加的鎖。
怎么避免這種情況呢?可以在del釋放鎖之前做一個判斷,驗證當前的鎖是不是自己加的鎖。
至于具體的實現,可以在加鎖的時候把當前的線程ID當做value,并在刪除之前驗證key對應的value是不是自己線程的ID。
加鎖:
String threadId = Thread.currentThread().getId() set(key,threadId ,30,NX)
解鎖:
if(threadId .equals(redisClient.get(key))){ del(key) }
但是,這樣做又隱含了一個新的問題,判斷和釋放鎖是兩個獨立操作,不是原子性。
我們都是追求極致的程序員,所以這一塊要用Lua腳本來實現:
String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; redisClient.eval(luaScript , Collections.singletonList(key), Collections.singletonList(threadId));
這樣一來,驗證和刪除過程就是原子操作了。
還是剛才第二點所描述的場景,雖然我們避免了線程A誤刪掉key的情況,但是同一時間有A,B兩個線程在訪問代碼塊,仍然是不完美的。
怎么辦呢?我們可以讓獲得鎖的線程開啟一個守護線程,用來給快要過期的鎖“續航”。
當過去了29秒,線程A還沒執行完,這時候守護線程會執行expire指令,為這把鎖“續命”20秒。守護線程從第29秒開始執行,每20秒執行一次。
當線程A執行完任務,會顯式關掉守護線程。
另一種情況,如果節點1 忽然斷電,由于線程A和守護線程在同一個進程,守護線程也會停下。這把鎖到了超時的時候,沒人給它續命,也就自動釋放了。
以上是“怎么使用redis實現分布式鎖”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。