分佈式Redis的分佈式鎖 Redlock

連接html

Distributed locks with Redisgit

引言

以前本身在用redis來實現分佈式鎖的時候都是基於單個Redis實例,也就是說Redis自己是有單點故障的,Redis的官方文檔介紹了一種"自認爲"合理的算法,Redlock來實現分佈式Redis下的分佈式鎖。github

Martin Kleppmann寫了一篇文章分析Redlock。而後redis的做者寫了一篇反駁的文章這裏。加油。redis

Redlock實現庫

雖而後面的算法是同樣的,不過這個點贊數確實服。算法

單點Redis鎖

先簡單回顧一下單點的Redis鎖是怎麼實現的。bash

獲取鎖

SET resource_name my_random_value NX PX 30000

客戶端A在Redis上設置一個特定的鍵值對,同時給一個超時時間(避免死鎖)。其餘客戶端在訪問的時候先看看這個key是否已經存在,而且值等於my_random_value。若是已存在就等待,不然就獲取成功,執行業務代碼。resource_namemy_random_value是全部客戶端都知道而且共享的。服務器

釋放鎖

if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

對比key獲取到的對應的value是否相等,若是相等,就刪除(釋放),不然就返回失敗。架構

以前也寫過一篇文章dom

單點Redis鎖的缺陷

這個缺陷其實很明顯,若是隻有一個Redis實例,這個掛了,全部依賴他的服務都掛了。顯然不太適合大型的應用。異步

簡單的Redis主從架構碰到的問題

爲了不單點故障,咱們給Redis作一個Master/Slave的主從架構,一個Master,一臺Slave。下面就會碰到這麼一個問題。下面是使用場景。

  1. 客戶端A在Master上獲取到一個鎖。
  2. Master把這個數據同步到Slave的時候掛了(由於Master和Slave之間同步是異步的)。
  3. Slave變成了Master。
  4. 客戶端B經過相同的key,和value獲取到鎖。分佈式鎖失效

Redlock算法

假設咱們有N(假設5)個Redis master實例,全部節點相互獨立,而且業務系統也是單純的調用,並無什麼其餘的相似消息重發之類的輔助系統。下面來模擬一下算法:

  1. 客戶端獲取服務器當前的的時間t0,毫秒數。
  2. 使用相同的key和value依次向5個實例獲取鎖。客戶端在獲取鎖的時候自身設置一個遠小於業務鎖須要的持續時間的超時時間。舉個例子,假設鎖須要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就好。

相關文章
相關標籤/搜索