基於 Redis 的分佈式鎖 Redlock

這篇文章主要是對 Redis 官方網站刊登的 Distributed locks with Redis 部份內容的總結和翻譯。程序員

什麼是 RedLock

Redis 官方站這篇文章提出了一種權威的基於 Redis 實現分佈式鎖的方式名叫 Redlock,此種方式比原先的單節點的方法更安全。它能夠保證如下特性:redis

  1. 安全特性:互斥訪問,即永遠只有一個 client 能拿到鎖
  2. 避免死鎖:最終 client 均可能拿到鎖,不會出現死鎖的狀況,即便本來鎖住某資源的 client crash 了或者出現了網絡分區
  3. 容錯性:只要大部分 Redis 節點存活就能夠正常提供服務

怎麼在單節點上實現分佈式鎖

SET resource_name my_random_value NX PX 30000算法

主要依靠上述命令,該命令僅當 Key 不存在時(NX保證)set 值,而且設置過時時間 3000msPX保證),值 my_random_value 必須是全部 client 和全部鎖請求發生期間惟一的,釋放鎖的邏輯是:安全

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

上述實現能夠避免釋放另外一個 client 建立的鎖,若是隻有 del 命令的話,那麼若是 client1 拿到 lock1 以後由於某些操做阻塞了很長時間,此時 Redislock1 已通過期了而且已經被從新分配給了 client2,那麼 client1 此時再去釋放這把鎖就會形成 client2 本來獲取到的鎖被 client1 無端釋放了,但如今爲每一個 client 分配一個 uniquestring 值能夠避免這個問題。至於如何去生成這個 unique string,方法不少隨意選擇一種就好了。網絡

Redlock 算法

算法很易懂,起 5master 節點,分佈在不一樣的機房儘可能保證可用性。爲了得到鎖,client 會進行以下操做:dom

  1. 獲得當前的時間,微秒(ms)單位
  2. 嘗試順序地在 5 個實例上申請鎖,固然須要使用相同的 keyrandom value,這裏一個 client 須要合理設置與 master 節點溝通的 timeout 大小,避免長時間和一個 fail 了的節點浪費時間
  3. client 在大於等於 3master 上成功申請到鎖的時候,且它會計算申請鎖消耗了多少時間,這部分消耗的時間採用得到鎖的當下時間減去第一步得到的時間戳獲得,若是鎖的持續時長(lock validity time)比流逝的時間多的話,那麼鎖就真正獲取到了。
  4. 若是鎖申請到了,那麼鎖真正的 lock validity time 應該是 origin(lock validity time) - 申請鎖期間流逝的時間
  5. 若是 client 申請鎖失敗了,那麼它就會在少部分申請成功鎖的 master 節點上執行釋放鎖的操做,重置狀態

失敗重試

若是一個 client 申請鎖失敗了,那麼它須要稍等一會在重試避免多個 client 同時申請鎖的狀況,最好的狀況是一個 client 須要幾乎同時向 5master 發起鎖申請。另外就是若是 client 申請鎖失敗了它須要儘快在它曾經申請到鎖的 master 上執行 unlock 操做,便於其餘 client 得到這把鎖,避免這些鎖過時形成的時間浪費,固然若是這時候網絡分區使得 client 沒法聯繫上這些 master,那麼這種浪費就是不得不付出的代價了。分佈式

放鎖

放鎖操做很簡單,就是依次釋放全部節點上的鎖就好了性能

性能、崩潰恢復和 fsync

若是咱們的節點沒有持久化機制,client5master 中的 3 個處得到了鎖,而後其中一個重啓了,這時注意:網站

整個環境中又出現了 3 個 master 可供另外一個 client 申請同一把鎖!lua

這違反了互斥性。

若是咱們開啓了 AOF 持久化那麼狀況會稍微好轉一些,由於 Redis 的過時機制是語義層面實現的,因此在 server 掛了的時候時間依舊在流逝,重啓以後鎖狀態不會受到污染。可是考慮斷電以後呢,AOF 部分命令沒來得及刷回磁盤直接丟失了,除非咱們配置刷回策略爲 fsnyc = always,但這會損傷性能。解決這個問題的方法是,當一個節點重啓以後,咱們規定在max TTL 期間它是不可用的,這樣它就不會干擾本來已經申請到的鎖,等到它 crash 前的那部分鎖都過時了,環境不存在歷史鎖了,那麼再把這個節點加進來正常工做。

寫在最後

這是一個不定時更新的、披着程序員外衣的文青小號。既分享極客技術,也記錄人間煙火。

相關文章
相關標籤/搜索