溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Redis分布式鎖怎么應(yīng)用

發(fā)布時間:2021-12-07 16:05:50 來源:億速云 閱讀:177 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“Redis分布式鎖怎么應(yīng)用”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Redis分布式鎖怎么應(yīng)用”吧!

分布式鎖

在單進程應(yīng)用中,當(dāng)一段代碼同一時間內(nèi)只能由一個線程執(zhí)行時,

多線程下可能會出錯,例如兩個線程同時對一個數(shù)字做累加,兩個線程同時拿到了該數(shù)字,例如40,一個線程加了10,一個線程加了20,正確結(jié)果應(yīng)該是70,

但由于兩個線程在自己的內(nèi)存中一個算出的是50,一個算出的是60,此時二者都將自己的結(jié)果往該數(shù)字原本的地方寫(保存),

這時候,肯定會有一個線程的值會被覆蓋,因為讀取->計算->保存 并不是原子操作(原子操作是指不會被線程調(diào)度機制打斷的操作,這種操作一旦開始,就會一直運行結(jié)束,中間不會有任何線程切換),

也就是說最終的結(jié)果要么是50,要么是60,而不可能是70(出現(xiàn)并發(fā)或并行的情況下,這種情況大概率會發(fā)生),

Redis分布式鎖怎么應(yīng)用

單進程應(yīng)用發(fā)生這種情況時,可以由程序提供的鎖語義直接上鎖(例如java中的sychornized)保證該段代碼只會被一個線程執(zhí)行,按照順序來進行,結(jié)果將是正確的。

在分布式應(yīng)用中,由于一臺機器上可能跑著相同的應(yīng)用進程,或者在不同的機器上跑著,原本程序自帶的語義鎖已經(jīng)無法起到作用,

因為相同的代碼可能是在不同的機器、進程中執(zhí)行,所以此時需要一個能夠讓不同機器、進程中,相同的應(yīng)用代碼執(zhí)行到同一段代碼時,也能夠按照順序執(zhí)行(或者同一時間內(nèi)只有一個線程能夠執(zhí)行),

這就需要用到中間件來協(xié)調(diào),可以實現(xiàn)分布式鎖的中間件有很多,redis就是其中一個。

redis實現(xiàn)分布式鎖的原理

redis中分布式鎖的原理其實就是在redis當(dāng)中設(shè)置一個值(當(dāng)然要保證分布式應(yīng)用連的都是同一個redis,以這個redis作為中間點,否則當(dāng)然是沒用的),這個值只能由一個線程來存放,當(dāng)其他線程(或者不同機器上的進程)也來存放時,發(fā)現(xiàn)這個值已經(jīng)存在了,就說明此時已經(jīng)有人在用這把鎖了,這時候要么進行重試等待,要么進行放棄。

設(shè)置一般使用 SETNX (set if not exists) 指令,如果該值沒有,則進行設(shè)置,有了則不設(shè)置,這就是拿鎖的關(guān)鍵了,當(dāng)拿到鎖的人執(zhí)行處理完畢后,再調(diào)用 DEL 執(zhí)行進行鎖的釋放。

死鎖問題

使用 SETNX 和 DEL 實現(xiàn)了分布式鎖,但是有一種情況,如果一個線程進行了 SETNX 拿到鎖成功后,突然這個線程因為某種原因崩潰了,導(dǎo)致沒有進行 DEL 釋放鎖,

那么此時,將會導(dǎo)致其他所有的應(yīng)用都再也沒辦法拿到這把鎖,也就是 死鎖 ,這個問題的解決方式是將鎖設(shè)置一個有效期,到了有效期之后該鎖將被自動釋放,

使用 EXPIRE 可以給鎖設(shè)置一個有效期,如下

SETNX LOCK-KEY-NAME true
EXPIRE LOCK-KEY-NAME 5

但是還有一個問題,因為 SETNX 和 EXPIRE 是分為兩個指令執(zhí)行的,這中間依然有可能出現(xiàn) SETNX 執(zhí)行完畢后,由于認(rèn)為或者機器、程序發(fā)生的故障 導(dǎo)致 EXPIRE 沒有執(zhí)行成功,此時還是有可能會發(fā)生死鎖,

Redis分布式鎖怎么應(yīng)用

事務(wù)能不能解決這個問題?

NO,因為 EXPIRE 是依賴 SETNX 的執(zhí)行結(jié)果執(zhí)行的,只有 SETNX 成功后,才能進行 EXPIRE,否則是不可以執(zhí)行的,事務(wù)里并沒有 if else 的分支邏輯,要么全部執(zhí)行,要么一個都不執(zhí)行。

在 redis2.8 的版本中,引入了set指令的拓展參數(shù),可以讓 SETNX 和 EXPIRE 同時執(zhí)行(原子),解決了超時問題,

SET LOCK-KEY-NAME true ex 5 nx

超時問題

上面雖然說到利用給鎖設(shè)置過期時間解決可能會發(fā)生的死鎖問題,但是萬一我的程序代碼執(zhí)行時間超過了設(shè)置的過期時間,這時候鎖自動釋放了,但是我的代碼還沒執(zhí)行完畢,其他人又進行執(zhí)行了,導(dǎo)致結(jié)果出錯怎么辦?

在一般的開發(fā)場景中,我們會盡量將鎖的時間設(shè)置的長一些,例如60s,一般應(yīng)用程序在60s內(nèi)都能執(zhí)行完畢,但是怕就怕的是較真,如果60s內(nèi)也執(zhí)行不完怎么辦?

此時可以使用一種續(xù)期的方案,就是當(dāng)程序在執(zhí)行過程中,不斷的判斷鎖是否快要過期,代碼是否執(zhí)行完畢,如果快過期了沒有執(zhí)行完畢,就將這把鎖進行續(xù)期,保證鎖不會被自動釋放,直到我們的代碼執(zhí)行完畢為止,這種方案在java中由一個叫做 redisson 的框架實現(xiàn)了,可以直接引入使用。

鎖誤放問題

在鎖的使用過程中,很有可能出現(xiàn)其他應(yīng)用沒有拿到鎖,但是也執(zhí)行了 DEL 指令,將我們正在執(zhí)行中的程序的鎖釋放了,導(dǎo)致其他地方拿到鎖,進入代碼段開始執(zhí)行,

這里的解決方式是,在SETNX的時候,可以將value設(shè)置成一個隨機生成并全局唯一的一串?dāng)?shù)字或字符,該線程一直持有字符,在釋放鎖的時候,將字符與鎖中的字符進行比對,如果匹配,則可以進行釋放鎖,如果不匹配,說明是其他人誤放,此時拒絕釋放,

但是判斷字符是否相同與釋放鎖并不是原子操作,redis也并不提供這么一種命令,所以我們考慮使用lua腳本執(zhí)行這幾步操作(redisson也實現(xiàn)了),

最重要的一點是,程序中使用釋放鎖的入口一定要統(tǒng)一,萬一有的應(yīng)用程序不使用上面所述的方法釋放,直接使用 DEL ,那么上面說的方案就沒用了(筆者為了測試,直接用DEL釋放過)。

可重入性

可重入性是指線程在持有鎖的情況下,再次請求加鎖,如果一個鎖支持同一個線程的多次加鎖,那么這個鎖就是可重入的,Java中的 ReentrantLock 就是可重入鎖,大致的原理就是每次獲取到鎖后對一個數(shù)字進行 +1,每次釋放的時候進行 -1,當(dāng)數(shù)字為0時,分布式鎖被釋放,

redis鎖如果要支持可重入性,也需要用上面的方式進行支持,不過該邏輯加重了復(fù)雜性,一般推薦將需要鎖的代碼段進行邏輯調(diào)整,避免重復(fù)獲取分布式鎖來處理。(當(dāng)然redisson也支持了可重入鎖)

Redlock

上面的方式看起來沒有太多的問題了,但是由于redis本身可能也會發(fā)生問題,例如在Sentinel集群中,主節(jié)點掛掉,從節(jié)點變成主節(jié)點,但是客戶端這時候是不知道的,

如果客戶端在剛剛掛掉的主節(jié)點上SETNX成功了,但是這把鎖還沒有同步到從節(jié)點中,從節(jié)點這時候變成了主節(jié)點,這時候新主節(jié)點中沒有這把鎖的信息,

此時另一個客戶端來請求這把鎖,直接 SETNX 成功,又導(dǎo)致了兩個客戶端同時在執(zhí)行相同的代碼,又出現(xiàn)了不安全性,

Redis分布式鎖怎么應(yīng)用

為此業(yè)界提供了叫做 Redlock 的解決方案,原理大致是,提供多臺redis實例,這些實例之間相互獨立,沒有主從關(guān)系(沒有任何關(guān)系),同其他分布式算法一樣,使用了大多數(shù)機制,

加鎖時,它會向過半節(jié)點發(fā)出 set(key, value, nx = True, ex = xxx)指令,只要過半節(jié)點設(shè)置成功,這把鎖就算拿到了,釋放鎖時向所有節(jié)點發(fā)出 DEL 指令,

Redlock算法(Redisson已支持)需要考慮出錯重試,時鐘漂移等等細節(jié)問題,同時Redlock需要向多個節(jié)點進行讀寫,性能將要比單例redis下降,

如果業(yè)務(wù)場景對錯誤的發(fā)生容忍度很低,又可以接受性能稍微有點下降,可以考慮采用Redlock算法。

感謝各位的閱讀,以上就是“Redis分布式鎖怎么應(yīng)用”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Redis分布式鎖怎么應(yīng)用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI