Redis分布式锁(Redlock官方文档的理解)
生活随笔
收集整理的這篇文章主要介紹了
Redis分布式锁(Redlock官方文档的理解)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Redis分布式鎖(Redlock官方文檔的理解)
我github博客原文
官網(wǎng)解釋
分布式鎖在許多不同進(jìn)程下需要對(duì)共享資源進(jìn)行互斥操作的環(huán)境下,十分需要
Redis作者提出了 Redlock 算法
開(kāi)始介紹:
安全和活躍度(可靠性)保障(Safety and Liveness)
需要設(shè)計(jì)合理分布式鎖,并滿足基本的保障 1.安全 -> 互斥屬性,在任何條件下,只允許一個(gè)客戶端拿到鎖 2.活躍度(可靠性)A -> 死鎖檢測(cè),即使有獲取到鎖的客戶端崩潰或者不可用,但是最終鎖還是能被獲取到 3.活躍度(可靠性)B -> 容錯(cuò),只要大部分的redis節(jié)點(diǎn)都存活,客戶端就能夠獲取鎖和釋放鎖 復(fù)制代碼為什么故障恢復(fù)的實(shí)現(xiàn)還不足夠
有個(gè)Master + slave 1.客戶端A獲取鎖 2.master 在命令傳播給slave前就崩潰了 3.slave這時(shí)候還不存在key,所以當(dāng)它被晉升成master時(shí) 4.客戶端B嘗試獲取鎖,就被獲取到了-> 這時(shí)候就不滿足redis分布式鎖的安全性了在極端情況下,集群服務(wù)發(fā)生失敗時(shí),多客戶端可能同時(shí)獲取鎖 復(fù)制代碼單實(shí)例的正確實(shí)現(xiàn)
在解決上述問(wèn)題前,先把基本的redis分布式鎖的設(shè)計(jì)做好
當(dāng)我們獲取鎖的時(shí)候,執(zhí)行下面命令行:
SET resource_name my_random_value NX PX 30000 NX表示當(dāng)key不存在才能設(shè)置成功 PX表示超時(shí)時(shí)間 my_random_value 需要在所有客戶端和獲取鎖的請(qǐng)求中表示唯一 復(fù)制代碼釋放鎖,需要帶著 my_random_value 作標(biāo)識(shí)然后再del,2個(gè)操作作原子,所以推薦使用lua腳本
if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1]) elsereturn 0 end 復(fù)制代碼說(shuō)明
1.這樣就能有效的阻止其他客戶端生成鎖。(應(yīng)該不用多說(shuō)明吧。) 2.my_random_value 應(yīng)該怎么設(shè)置,反正容量越小,消耗越小越好,文檔上給出是使用clientId加上時(shí)間戳或者使用RC4算法 3.expire的時(shí)間設(shè)置,我們稱作鎖有效時(shí)間,是鎖自動(dòng)釋放時(shí)間 + 客戶端需要在鎖時(shí)間內(nèi)執(zhí)行的事務(wù)所需要的時(shí)間(在其他客戶端獲取到鎖之前) = 鎖自動(dòng)釋放時(shí)間 + 客戶端處理業(yè)務(wù)(鎖期間)的時(shí)間 考慮到互斥的保證,這個(gè)時(shí)間窗口應(yīng)該限制在鎖被獲取之后復(fù)制代碼基本操作介紹了,現(xiàn)在可以優(yōu)化了
Redlock算法
在分布式版本中,我們假設(shè)我們有N個(gè)redis 的matser,各自獨(dú)立,沒(méi)有任何關(guān)系(不在一個(gè)cluster下),可以部署在不同的服務(wù)器或是虛擬機(jī)上,假設(shè)N設(shè)置成5客戶端獲取鎖的操作: 1. 客戶端A獲取當(dāng)前時(shí)間戳 2. 客戶端A嘗試在所有N個(gè)redis中獲取鎖(有序的),使用同樣的key和value,這一步中,由于需要遍歷去請(qǐng)求多個(gè)redis服務(wù)(set的命令請(qǐng)求,之前理解成業(yè)務(wù)的處理時(shí)間),可能導(dǎo)致阻塞,需要設(shè)置超時(shí)時(shí)間,假設(shè)鎖自動(dòng)釋放的時(shí)間是10s,那么這個(gè)超時(shí)時(shí)間可以設(shè)置在 5-50毫秒范圍,這一步,防止客戶端在獲取鎖期間由于redis節(jié)點(diǎn)崩潰不可用導(dǎo)致獲取鎖曹氏 3. 客戶端A獲取鎖時(shí),再獲取當(dāng)前時(shí)間戳,與步驟1的時(shí)間相減,得到獲取鎖消耗的時(shí)間,在鎖有效期內(nèi),當(dāng)且僅當(dāng)客戶端A拿到大部分(至少3)的鎖時(shí),分布式鎖才可以被正式獲取 4. 每次當(dāng)鎖被獲取到時(shí)(從每個(gè)master獲取),有效時(shí)間可以被設(shè)置成初始有效時(shí)間減去獲取鎖消耗的時(shí)間 (因?yàn)橐呀?jīng)獲取鎖了,所以獲取鎖的時(shí)間不用算進(jìn)去) 5. 假設(shè)在步驟2中客戶端A獲取不到鎖,比如拿不到大部分的鎖,或者是鎖還沒(méi)超時(shí),它需要把自己在少部分redis上拿到的鎖釋放掉復(fù)制代碼這個(gè)算法是異步的嗎
這個(gè)算法依賴的一個(gè)假設(shè):是不同進(jìn)程的各自的時(shí)鐘精確率(就是表走得快走得慢,而且誤差跟鎖釋放時(shí)間比小得多)一樣,而且不(需要)作時(shí)間的同步。類似于,現(xiàn)實(shí)生活中,每個(gè)人都各自使用自己的電腦(以及電腦上的時(shí)間),通常也不會(huì)有什么問(wèn)題; 在這個(gè)情況下,我們需要更具體的說(shuō)明互斥規(guī)則:它(互斥規(guī)則)保證僅僅只有獲取鎖的哭護(hù)短能夠在鎖的有效時(shí)間內(nèi)結(jié)束它的工作,減去某個(gè)很小的時(shí)間差(幾毫秒,用來(lái)作補(bǔ)償)復(fù)制代碼失敗重試(這里指的是獲取鎖的失敗)
當(dāng)客戶端獲取不到鎖,它應(yīng)該在之后一個(gè)隨機(jī)時(shí)間點(diǎn)重試,這為了避免多個(gè)客戶端嘗試同時(shí)獲取同一個(gè)資源(類似腦裂的情況,大概意思就是競(jìng)爭(zhēng)了一堆,卻發(fā)現(xiàn),沒(méi)人拿到鎖),客戶端拿到鎖越快(早),腦裂的情況越小(或者重試的需要越小),所以理想情況下,客戶端可以同時(shí)(多路復(fù)用)發(fā)送set命令給各個(gè)master復(fù)制代碼釋放鎖
鎖釋放步驟很簡(jiǎn)單,就是把所有master實(shí)例上的鎖釋放,并不需要關(guān)心客戶端在該實(shí)例上有沒(méi)有成功得到鎖復(fù)制代碼安全討論
假設(shè)一個(gè)客戶端能夠獲取大多數(shù)實(shí)例上的鎖,所有實(shí)例都會(huì)存在一個(gè)key,并且有個(gè)相同的超時(shí)時(shí)間,但是這個(gè)key的設(shè)置的時(shí)間點(diǎn)是不一樣的(就是set的時(shí)候都不一樣,因?yàn)槭琼樞驁?zhí)行,總會(huì)有時(shí)間差),所以key會(huì)在不同的時(shí)間超時(shí)。但是當(dāng)?shù)谝粋€(gè)key被至少設(shè)成T1,最后一個(gè)key被設(shè)成T2(超時(shí)時(shí)間),我們可以確認(rèn)第一個(gè)key會(huì)存在至少 MIN_VALIDITY=TTL-(T2-T1)-CLOCK_DRIFT 的時(shí)間,而且其他的key會(huì)失效的更晚,我們要同時(shí)將時(shí)間設(shè)置成這個(gè) 當(dāng)一個(gè)key被set(NX)的時(shí)候,其他key就無(wú)法被別的客戶端set了---- 總的說(shuō)的就是時(shí)間設(shè)置還有并發(fā)控制 復(fù)制代碼可靠性討論
1. 自動(dòng)釋放的鎖最終還能被獲取到; 2. 客戶端通常會(huì)協(xié)助刪除那些沒(méi)獲取到的鎖(步驟5)、鎖獲取到并且工作結(jié)束的,使得并不需要等待鎖超時(shí)才能重新獲取鎖; 3. 客戶端需要重試獲取鎖,為了資源競(jìng)爭(zhēng),他們重試的等待時(shí)間應(yīng)該大于需要從大多數(shù)實(shí)例上獲取的時(shí)間復(fù)制代碼 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Redis分布式锁(Redlock官方文档的理解)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 修改Docker容器字符编码为-zh_C
- 下一篇: java-自定义数据排序