redisson redlock(基于redisson框架和redis集群使用分布式锁)
一、關(guān)于分布式鎖的兩篇文章
文章1
文章2
二、redis分布式鎖存在的問題
redis實(shí)現(xiàn)分布式鎖有很多種方案,比較完善的方案應(yīng)該是用setNx + lua進(jìn)行實(shí)現(xiàn)。簡(jiǎn)單實(shí)現(xiàn)如下:
- java代碼-加鎖,相當(dāng)于
- lua腳本-解鎖,原子性操作
- 解釋
- NX:僅在不存在 key 的時(shí)候才能被執(zhí)行成功;
- PX:失效時(shí)間,傳入 30000,就是 30s 后自動(dòng)釋放鎖;
- unique_value:就是隨機(jī)值,可以是線程號(hào)之類的。主要是為了更安全的釋放鎖,釋放鎖的時(shí)候使用腳本告訴 Redis: 只有 key 存在并且存儲(chǔ)的值和我指定的值一樣才能刪除成功。
- 為什么要設(shè)置隨機(jī)值:主要是為了防止鎖被其他客戶端刪除。
注意:
注意,不能一味認(rèn)為鎖過期的時(shí)間應(yīng)該比key的expire要長(zhǎng),因?yàn)榻酉聛?lái)要介紹的redisson框架中有續(xù)期機(jī)制(看門狗機(jī)制),該機(jī)制的核心就是:如果線程仍舊沒有執(zhí)行完,那么redisson會(huì)自動(dòng)給redis中的目標(biāo)key延長(zhǎng)超時(shí)時(shí)間
在分布式系統(tǒng)中,為了避免單點(diǎn)故障,提高可靠性,redis都會(huì)采用主從架構(gòu),當(dāng)主節(jié)點(diǎn)掛了后,從節(jié)點(diǎn)會(huì)作為主繼續(xù)提供服務(wù)。該種方案能夠滿足大多數(shù)的業(yè)務(wù)場(chǎng)景,但是對(duì)于要求強(qiáng)一致性的場(chǎng)景如交易,該種方案還是有漏洞的,原因如下:
因此,上述基于redis實(shí)現(xiàn)的分布式鎖只是滿足了AP,并沒有滿足C。
三、redlock
單實(shí)例肯定不是很可靠吧?加鎖成功之后,結(jié)果 Redis 服務(wù)宕機(jī)了,就涼了。這時(shí)候會(huì)提出來(lái)將 Redis 主從部署。即使是主從,也是存在巧合的!
- 主從結(jié)構(gòu)中存在明顯的競(jìng)態(tài):
有時(shí)候程序就是這么巧,比如說(shuō)正好一個(gè)節(jié)點(diǎn)掛掉的時(shí)候,多個(gè)客戶端同時(shí)取到了鎖。如果你可以接受這種小概率錯(cuò)誤,那用這個(gè)基于復(fù)制的方案就完全沒有問題。
- 如果使用集群呢
我們知道對(duì)集群進(jìn)行加鎖的時(shí)候,其實(shí)是通過 CRC16 的 hash 函數(shù)來(lái)對(duì) key 進(jìn)行取模,將結(jié)果路由到預(yù)先分配過 slot 的相應(yīng)節(jié)點(diǎn)上。發(fā)現(xiàn)其實(shí)還是發(fā)到單個(gè)節(jié)點(diǎn)上的!
- 正是因?yàn)樯鲜鰎edis分布式鎖存在的一致性問題,redis作者提出了一個(gè)更加高級(jí)的基于redis實(shí)現(xiàn)的分布式鎖——RedLock。原文可參考 Distributed locks with Redis,也可以參考這篇文章。
RedLock是基于redis實(shí)現(xiàn)的分布式鎖,它能夠保證以下特性:
- 互斥性:在任何時(shí)候,只能有一個(gè)客戶端能夠持有鎖;
- 避免死鎖:當(dāng)客戶端拿到鎖后,即使發(fā)生了網(wǎng)絡(luò)分區(qū)或者客戶端宕機(jī),也不會(huì)發(fā)生死鎖;(利用key的存活時(shí)間)
- 容錯(cuò)性:只要多數(shù)節(jié)點(diǎn)的redis實(shí)例正常運(yùn)行,就能夠?qū)ν馓峁┓?wù),加鎖或者釋放鎖;
而非redLock是無(wú)法滿足互斥性的,上面已經(jīng)闡述過了原因。
假設(shè)有N個(gè)redis的master節(jié)點(diǎn),這些節(jié)點(diǎn)是相互獨(dú)立的(不需要主從或者其他協(xié)調(diào)的系統(tǒng))。N推薦為奇數(shù)。具體算法如下:
- 注意:為什么N推薦為奇數(shù)呢?
-
原因1:本著最大容錯(cuò)的情況下,占用服務(wù)資源最少的原則,2N+1和2N+2的容災(zāi)能力是一樣的,所以采用2N+1;比如,5臺(tái)服務(wù)器允許2臺(tái)宕機(jī),容錯(cuò)性為2,6臺(tái)服務(wù)器也只能允許2臺(tái)宕機(jī),容錯(cuò)性也是2,因?yàn)橐蟪^半數(shù)節(jié)點(diǎn)存活才OK。
-
原因2:假設(shè)有6個(gè)redis節(jié)點(diǎn),client1和client2同時(shí)向redis實(shí)例獲取同一個(gè)鎖資源,那么可能發(fā)生的結(jié)果是——client1獲得了3把鎖,client2獲得了3把鎖,由于都沒有超過半數(shù),那么client1和client2獲取鎖都失敗,對(duì)于奇數(shù)節(jié)點(diǎn)是不會(huì)存在這個(gè)問題。
參考文章
-
當(dāng)客戶端無(wú)法獲取到鎖時(shí),應(yīng)該隨機(jī)延時(shí)后進(jìn)行重試,防止多個(gè)客戶端在同一時(shí)間搶奪同一資源的鎖(會(huì)導(dǎo)致腦裂,最終都不能獲取到鎖)。客戶端獲得超過半數(shù)節(jié)點(diǎn)的鎖花費(fèi)的時(shí)間越短,那么腦裂的概率就越低。所以,理想的情況下,客戶端最好能夠同時(shí)(并發(fā))向所有redis發(fā)出set命令。
-
當(dāng)客戶端從多數(shù)節(jié)點(diǎn)獲取鎖失敗時(shí),應(yīng)該盡快釋放已經(jīng)成功獲取的鎖,這樣其他客戶端不需要等待鎖過期后再獲取。(如果存在網(wǎng)絡(luò)分區(qū),客戶端已經(jīng)無(wú)法和redis進(jìn)行通信,那么此時(shí)只能等待鎖過期后自動(dòng)釋放)
不明白為什么會(huì)發(fā)生腦裂???
向所有redis實(shí)例發(fā)送釋放鎖命令即可,不需要關(guān)心redis實(shí)例有沒有成功上鎖。
redisson在加鎖的時(shí)候,key=lockName, value=uuid + threadID,采用set結(jié)構(gòu)存儲(chǔ),并包含了上鎖的次數(shù)(支持可重入);解鎖的時(shí)候通過hexists判斷key和value是否存在,存在則解鎖;這里不會(huì)出現(xiàn)誤解鎖
-
如何提升分布式鎖的性能?以每分鐘執(zhí)行多少次acquire/release操作作為性能指標(biāo),一方面通過增加redis實(shí)例可用降低響應(yīng)延遲,另一方面,使用非阻塞模型,一次發(fā)送所有的命令,然后異步讀取響應(yīng)結(jié)果,這里假設(shè)客戶端和redis之間的RTT差不多。
-
如果redis沒用使用備份,redis重啟后,那么會(huì)丟失鎖,導(dǎo)致多個(gè)客戶端都能獲取到鎖。通過AOF持久化可以緩解這個(gè)問題。redis key過期是unix時(shí)間戳,即便是redis重啟,那么時(shí)間依然是前進(jìn)的。但是,如果是斷電呢?redis在啟動(dòng)后,可能就會(huì)丟失這個(gè)key(在寫入或者還未寫入磁盤時(shí)斷電了,取決于fsync的配置),如果采用fsync=always,那么會(huì)極大影響性能。如何解決這個(gè)問題呢?可以讓redis節(jié)點(diǎn)重啟后,在一個(gè)TTL時(shí)間段內(nèi),對(duì)客戶端不可用即可。
四、redlock已經(jīng)在最新本的redisson中被棄用了
看著 RedLock 好像是解決問題了:
那實(shí)際解決問題了么?推薦大家閱讀兩篇文章:
-
Martin Kleppmann:How to do distributed locking
-
Salvatore(Redis 作者):Is Redlock safe?
最終,兩方各持己見,沒有得出結(jié)論。具體的源碼分析棄用原因,可以參考這篇文章
五、結(jié)論
Redisson RedLock 是基于聯(lián)鎖 MultiLock 實(shí)現(xiàn)的,但是使用過程中需要自己判斷 key 落在哪個(gè)節(jié)點(diǎn)上,對(duì)使用者不是很友好。Redisson RedLock 已經(jīng)被棄用,直接使用普通的加鎖即可,會(huì)基于 wait 機(jī)制將鎖同步到從節(jié)點(diǎn),但是也并不能保證一致性。僅僅是最大限度的保證一致性。
基于MultiLock 實(shí)現(xiàn)的分布式鎖
總結(jié)
以上是生活随笔為你收集整理的redisson redlock(基于redisson框架和redis集群使用分布式锁)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 互联网日报 | 1月22日 星期五 |
- 下一篇: 你的实力就等于别人对待你的态度