在許多環境中,分布式鎖是一種非常有用的原語,其中不同的程序必須以互斥的方式與共享資源一起執行。
有許多庫和部落格文章描述了如何使用redis實現dlm(分布式鎖管理器),但是每個庫都使用不同的方法,而且許多庫使用的是一種簡單的方法,與稍微複雜的設計相比,可以獲得較低的保障。
此頁面試圖提供一種更典型的演算法來使用redis實現分布式鎖,我們提出了一種稱為redlock的演算法,它實現了一種我們認為比vanilla單例項方法更安全的dlm,我們希望社群將對其進行分析,提供反饋,並將其作為實施或更複雜或替代設計的起點。
我們將僅使用三個屬性對我們的設計進行建模,從我們的角度來看,這些屬性是以有效方式使用分布式鎖所需的最低保障。
安全屬性:相互排斥。在任何給定時刻,只有乙個客戶端可以持有鎖。
活力屬性a:無死鎖。最終即使鎖定資源的客戶端崩潰或被分割槽,也始終可以獲取鎖定。
活力屬性b:容錯。只要大多數redis節點啟動,客戶端就能夠獲取和釋放鎖。
為了理解我們想要改進的內容,讓我們分析大多數基於redis的分布式鎖庫的當前狀態。
使用redis鎖定資源的最簡單方法是在例項中建立金鑰,金鑰通常使用redis過期功能在有限的生存時間內建立,因此最終它將被釋放(我們列表中的屬性2),當客戶端需要釋放資源時,它會刪除金鑰。
從表面上看,這很有效,但存在乙個問題:這是我們架構中的單點故障,如果redis主機出現故障會怎樣?好吧,讓我們新增乙個從機!如果主伺服器不可用,則使用它,遺憾的是,這不可行。通過這樣做,我們無法實現互斥的安全屬性,因為redis主從複製是非同步的。
這種模式存在明顯的競爭條件:
客戶端a獲取主伺服器中的鎖
在對金鑰的寫入被傳輸到從伺服器之前,主伺服器崩潰了
從機被提公升為主機
客戶端b獲得與a已經持有鎖的相同資源的鎖。安全違反!
有時在特殊情況下,例如在故障期間,多個客戶端可以同時保持鎖定,這是完全正常的,如果是這種情況,你可以使用基於主從複製的解決方案,否則,我們建議實施本文件中描述的解決方案。
在嘗試克服上述單例項設定的限制之前,讓我們看看在這個簡單的例子中如何正確地做到這一點,因為在時常可以接收競爭條件的應用中,這實際上是乙個可行的解決方案,因為鎖定到單個例項是我們將用於此處描述的分布式演算法的基礎。
要獲得鎖,可採取的方法如下:
set resource_name my_random_value nx px 30000
該命令僅在金鑰尚不存在時才設定金鑰(nx選項),到期時間為30000毫秒(px選項),鍵的值設定為「myrandomvalue」,此值必須在所有客戶端和所有鎖定請求中都是唯一的,基本上使用隨機值以便以安全的方式釋放鎖,使用乙個告訴redis的指令碼:只有當金鑰存在並且金鑰中儲存的值正是我期望的那個時才刪除金鑰,這是通過以下lua指令碼完成的:
if redis.call("get",keys[1]) == ar**[1] then
return redis.call("del",keys[1])
else
return 0
end
redis分布式鎖
redis分布式鎖 直接上 我寫了四個redis分布式鎖的方法,大家可以提個意見 第一種方法 redis分布式鎖 param timeout public void lock long timeout thread.sleep 100 catch exception e override publi...
Redis分布式鎖
分布式鎖一般有三種實現方式 1.資料庫樂觀鎖 2.基於redis的分布式鎖 3.基於zookeeper的分布式鎖.首先,為了確保分布式鎖可用,我們至少要確保鎖的實現同時滿足以下四個條件 互斥性。在任意時刻,只有乙個客戶端能持有鎖。不會發生死鎖。即使有乙個客戶端在持有鎖的期間崩潰而沒有主動解鎖,也能保...
redis分布式鎖
使用redis的setnx命令實現分布式鎖 redis為單程序單執行緒模式,採用佇列模式將併發訪問變成序列訪問,且多個客戶端對redis的連線並不存在競爭關係。redis的setnx命令可以方便的實現分布式鎖。setnx key value 將key的值設為value,當且僅當key不存在。如給定的...