redlock java_Redlock分布式锁
這篇文章主要是對(duì) Redis 官方網(wǎng)站刊登的 Distributed locks with Redis 部分內(nèi)容的總結(jié)和翻譯。
什么是 RedLock
Redis 官方站這篇文章提出了一種權(quán)威的基于 Redis 實(shí)現(xiàn)分布式鎖的方式名叫 Redlock,此種方式比原先的單節(jié)點(diǎn)的方法更安全。它可以保證以下特性:
安全特性:互斥訪問,即永遠(yuǎn)只有一個(gè) client 能拿到鎖
避免死鎖:最終 client 都可能拿到鎖,不會(huì)出現(xiàn)死鎖的情況,即使原本鎖住某資源的 client crash 了或者出現(xiàn)了網(wǎng)絡(luò)分區(qū)
容錯(cuò)性:只要大部分 Redis 節(jié)點(diǎn)存活就可以正常提供服務(wù)
怎么在單節(jié)點(diǎn)上實(shí)現(xiàn)分布式鎖
SET resourcename myrandom_value NX PX 30000
主要依靠上述命令,該命令僅當(dāng) Key 不存在時(shí)(NX保證)set 值,并且設(shè)置過期時(shí)間 3000ms (PX保證),值 myrandomvalue 必須是所有 client 和所有鎖請(qǐng)求發(fā)生期間唯一的,釋放鎖的邏輯是:
ifredis.call("get",KEYS[1])==ARGV[1]then
returnredis.call("del",KEYS[1])
else
return0
end
上述實(shí)現(xiàn)可以避免釋放另一個(gè)client創(chuàng)建的鎖,如果只有 del 命令的話,那么如果 client1 拿到 lock1 之后因?yàn)槟承┎僮髯枞撕荛L(zhǎng)時(shí)間,此時(shí) Redis 端 lock1 已經(jīng)過期了并且已經(jīng)被重新分配給了 client2,那么 client1 此時(shí)再去釋放這把鎖就會(huì)造成 client2 原本獲取到的鎖被 client1 無故釋放了,但現(xiàn)在為每個(gè) client 分配一個(gè) unique 的 string 值可以避免這個(gè)問題。至于如何去生成這個(gè) unique string,方法很多隨意選擇一種就行了。
Redlock 算法
算法很易懂,起 5 個(gè) master 節(jié)點(diǎn),分布在不同的機(jī)房盡量保證可用性。為了獲得鎖,client 會(huì)進(jìn)行如下操作:
得到當(dāng)前的時(shí)間,微妙單位
嘗試順序地在 5 個(gè)實(shí)例上申請(qǐng)鎖,當(dāng)然需要使用相同的 key 和 random value,這里一個(gè) client 需要合理設(shè)置與 master 節(jié)點(diǎn)溝通的 timeout 大小,避免長(zhǎng)時(shí)間和一個(gè) fail 了的節(jié)點(diǎn)浪費(fèi)時(shí)間
當(dāng) client 在大于等于 3 個(gè) master 上成功申請(qǐng)到鎖的時(shí)候,且它會(huì)計(jì)算申請(qǐng)鎖消耗了多少時(shí)間,這部分消耗的時(shí)間采用獲得鎖的當(dāng)下時(shí)間減去第一步獲得的時(shí)間戳得到,如果鎖的持續(xù)時(shí)長(zhǎng)(lock validity time)比流逝的時(shí)間多的話,那么鎖就真正獲取到了。
如果鎖申請(qǐng)到了,那么鎖真正的 lock validity time 應(yīng)該是 origin(lock validity time) - 申請(qǐng)鎖期間流逝的時(shí)間
如果 client 申請(qǐng)鎖失敗了,那么它就會(huì)在少部分申請(qǐng)成功鎖的 master 節(jié)點(diǎn)上執(zhí)行釋放鎖的操作,重置狀態(tài)
失敗重試
如果一個(gè) client 申請(qǐng)鎖失敗了,那么它需要稍等一會(huì)在重試避免多個(gè) client 同時(shí)申請(qǐng)鎖的情況,最好的情況是一個(gè) client 需要幾乎同時(shí)向 5 個(gè) master 發(fā)起鎖申請(qǐng)。另外就是如果 client 申請(qǐng)鎖失敗了它需要盡快在它曾經(jīng)申請(qǐng)到鎖的 master 上執(zhí)行 unlock 操作,便于其他 client 獲得這把鎖,避免這些鎖過期造成的時(shí)間浪費(fèi),當(dāng)然如果這時(shí)候網(wǎng)絡(luò)分區(qū)使得 client 無法聯(lián)系上這些 master,那么這種浪費(fèi)就是不得不付出的代價(jià)了。
放鎖
放鎖操作很簡(jiǎn)單,就是依次釋放所有節(jié)點(diǎn)上的鎖就行了
性能、崩潰恢復(fù)和 fsync
如果我們的節(jié)點(diǎn)沒有持久化機(jī)制,client 從 5 個(gè) master 中的 3 個(gè)處獲得了鎖,然后其中一個(gè)重啟了,這是注意 整個(gè)環(huán)境中又出現(xiàn)了 3 個(gè) master 可供另一個(gè) client 申請(qǐng)同一把鎖! 違反了互斥性。如果我們開啟了 AOF 持久化那么情況會(huì)稍微好轉(zhuǎn)一些,因?yàn)?Redis 的過期機(jī)制是語義層面實(shí)現(xiàn)的,所以在 server 掛了的時(shí)候時(shí)間依舊在流逝,重啟之后鎖狀態(tài)不會(huì)受到污染。但是考慮斷電之后呢,AOF部分命令沒來得及刷回磁盤直接丟失了,除非我們配置刷回策略為 fsnyc = always,但這會(huì)損傷性能。解決這個(gè)問題的方法是,當(dāng)一個(gè)節(jié)點(diǎn)重啟之后,我們規(guī)定在 max TTL 期間它是不可用的,這樣它就不會(huì)干擾原本已經(jīng)申請(qǐng)到的鎖,等到它 crash 前的那部分鎖都過期了,環(huán)境不存在歷史鎖了,那么再把這個(gè)節(jié)點(diǎn)加進(jìn)來正常工作。
總結(jié)
以上是生活随笔為你收集整理的redlock java_Redlock分布式锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python外星人入侵不显示子弹_【Py
- 下一篇: 优盘怎么安装正版系统 如何用U盘安装正版