Redis 4.0.10 文檔(分佈式鎖)

Redis分佈式鎖

在許多環境中,分佈式鎖是一種很是有用的原語,其中不一樣的進程必須以互斥的方式與共享資源一塊兒運行。php

有許多庫和博客文章描述瞭如何使用Redis實現DLM(分佈式鎖管理器),可是每一個庫都使用不一樣的方法,並且許多庫使用的是一種簡單的方法,與稍微複雜的設計相比,能夠得到較低的保障。node

此頁面試圖提供一種更典型的算法來使用Redis實現分佈式鎖,咱們提出了一種稱爲Redlock的算法,它實現了一種咱們認爲比vanilla單實例方法更安全的DLM,咱們但願社區將對其進行分析,提供反饋,並將其做爲實施或更復雜或替代設計的起點。git

實現

在描述算法以前,這裏有幾個已經可用的實現的連接,可用於參考。github

安全性和活性保障

咱們將僅使用三個屬性對咱們的設計進行建模,從咱們的角度來看,這些屬性是以有效方式使用分佈式鎖所需的最低保障。面試

  1. 安全屬性:相互排斥。在任何給定時刻,只有一個客戶端能夠持有鎖。
  2. 活力屬性A:無死鎖。最終即便鎖定資源的客戶端崩潰或被分區,也始終能夠獲取鎖定。
  3. 活力屬性B:容錯。只要大多數Redis節點啓動,客戶端就可以獲取和釋放鎖。

爲何基於故障轉移的實現還不夠

爲了理解咱們想要改進的內容,讓咱們分析大多數基於Redis的分佈式鎖庫的當前狀態。redis

使用Redis鎖定資源的最簡單方法是在實例中建立密鑰,密鑰一般使用Redis過時功能在有限的生存時間內建立,所以最終它將被釋放(咱們列表中的屬性2),當客戶端須要釋放資源時,它會刪除密鑰。算法

從表面上看,這頗有效,但存在一個問題:這是咱們架構中的單點故障,若是Redis主機出現故障會怎樣?好吧,讓咱們添加一個從機!若是主服務器不可用,則使用它,遺憾的是,這不可行。經過這樣作,咱們沒法實現互斥的安全屬性,由於Redis主從複製是異步的。安全

這種模式存在明顯的競爭條件:服務器

  1. 客戶端A獲取主服務器中的鎖
  2. 在對密鑰的寫入被傳輸到從服務器以前,主服務器崩潰了
  3. 從機被提高爲主機
  4. 客戶端B得到與A已經持有鎖的相同資源的鎖。安全違反!

有時在特殊狀況下,例如在故障期間,多個客戶端能夠同時保持鎖定,這是徹底正常的,若是是這種狀況,你可使用基於主從複製的解決方案,不然,咱們建議實施本文檔中描述的解決方案。架構

使用單個實例正確實現

在嘗試克服上述單實例設置的限制以前,讓咱們看看在這個簡單的例子中如何正確地作到這一點,由於在時常能夠接收競爭條件的應用中,這其實是一個可行的解決方案,由於鎖定到單個實例是咱們將用於此處描述的分佈式算法的基礎。

要得到鎖,可採起的方法以下:

SET resource_name my_random_value NX PX 30000

該命令僅在密鑰尚不存在時才設置密鑰(NX選項),到期時間爲30000毫秒(PX選項),鍵的值設置爲「myrandomvalue」,此值必須在全部客戶端和全部鎖定請求中都是惟一的,基本上使用隨機值以便以安全的方式釋放鎖,使用一個告訴Redis的腳本:只有當密鑰存在而且密鑰中存儲的值正是我指望的那個時才刪除密鑰,這是經過如下Lua腳本完成的:

if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end
相關文章
相關標籤/搜索