Redlock實作庫
Java Redisson Star 9458
C# RedLock.net Star 259
Go redsync.go Star 249
#雖然後面的演算法是一樣的,不過這個按讚數確實服。
單點Redis鎖定
先簡單回顧一下單點的Redis鎖定是怎麼實現的。
取得鎖定
SET resource_name my_random_value NX PX 30000
客戶端A使用Redis設定一個鍵值對,並指定逾時時間以避免死鎖。當其他用戶端存取時,它們會先檢查該鍵是否已存在,且其值是否為「my_random_value」。如果已存在就等待,否則就取得成功,執行業務代碼。所有客戶端共用且已知的物件包括resource_name和my_random_value。
釋放鎖定
if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1])else return 0end
對比key取得到的對應的value是否相等,如果相等,就刪除(釋放),否則就回傳失敗。
單點Redis鎖定的缺陷
只有一個Redis實例時,發生故障會導致所有依賴它的服務都崩潰,這個缺陷異常明顯。顯然不太適合大型的應用。
簡單的Redis主從架構碰到的問題
為了避免單點故障,我們給Redis一個Master/Slave的主從架構,一個Master,一台Slave。下面就會碰到這麼一個問題。下面是使用場景。
客戶端A在Master上取得到一個鎖。
Master把這個資料同步到Slave的時候掛了(因為Master和Slave之間同步是異步的)。
Slave變成了Master。
客戶端B透過相同的key,和value取得到鎖定。分散式鎖定失效
Redlock演算法
#假設我們有N(假設5)個Redis master實例,所有節點相互獨立,且業務系統也是單純的調用,並沒有其他的類似訊息重發之類的輔助系統。下面來模擬演算法:
1.客戶端取得伺服器目前的的時間t0,毫秒數。
在5個實例中使用相同的key和value取得鎖定。在取得業務鎖時,用戶端會設定一個持續時間遠小於業務鎖所需的逾時時間。舉個例子,假設鎖需要10秒鐘,可以將超時時間設定在5-50毫秒之間。重寫後的句子: 為了避免客戶端在嘗試取得鎖時出現Redis已經故障的情況,需要採取措施。超時了之後就直接跳到下一個節點。
3.客戶端透過目前時間(t1)減去t0,計算取得鎖定所消耗的時間t2(=t1-t0)。只有t2小於鎖的業務有效時間(也就是第二步的10秒),並且,客戶端在至少3(5/2 1)台上獲取到鎖我們才認為鎖獲取成功。
4.如果鎖定已經獲取,那麼鎖定的業務有效時間為10s-t2。
5.如果客戶端沒有取得到鎖,可能是沒有在大於等於N/2 1個實例上取得鎖,也可能是有效時間(10s-t2)為負數,我們就嘗試去釋放鎖,即使是並沒有在那個節點上取得到。
鎖定的釋放
釋放比較簡單,直接刪除所有實例上對應的key就好。
以上是Redis中分散式鎖Redlock的範例分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!