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