關於Redis RedLock算法的爭論

內容簡介:Martin上來就問,咱們要鎖來幹啥呢?2個緣由:對於第1種緣由,咱們對鎖是有必定寬容度的,就算髮生了兩個節點同時工做,對系統的影響也僅僅是多付出了一些計算的成本,沒什麼額外的影響。這個時候 使用對於第2種緣由,對正確性嚴格要求的場景(好比訂單,或者消費),就算使用了 RedLock 算法仍然html

 

Martin上來就問,咱們要鎖來幹啥呢?2個緣由:redis

  1. 提高效率,用鎖來保證一個任務沒有必要被執行兩次。好比(很昂貴的計算)
  2. 保證正確,使用鎖來保證任務按照正常的步驟執行,防止兩個節點同時操做一份數據,形成文件衝突,數據丟失。

對於第1種緣由,咱們對鎖是有必定寬容度的,就算髮生了兩個節點同時工做,對系統的影響也僅僅是多付出了一些計算的成本,沒什麼額外的影響。這個時候 使用 單點的 Redis 就能很好的解決問題,沒有必要使用RedLock,維護那麼多的 Redis 實例,提高系統的維護成本。算法

對於第2種緣由,對正確性嚴格要求的場景(好比訂單,或者消費),就算使用了 RedLock 算法仍然 不能保證鎖的正確性 編程

咱們分析一下 RedLock 的有啥缺陷吧:安全

關於Redis RedLock算法的爭論

做者 Martin 給出這張圖,首先咱們上一講說過,RedLock中,爲了防止死鎖,鎖是具備過時時間的。這個過時時間被 Martin 抓住了小辮子。服務器

  • 若是 Client 1 在持有鎖的時候,發生了一次很長時間的 FGC 超過了鎖的過時時間。鎖就被釋放了。
  • 這個時候 Client 2 又得到了一把鎖,提交數據。
  • 這個時候 Client 1 從 FGC 中甦醒過來了,又一次提交數據。

這還了得,數據就發生了錯誤。RedLock 只是保證了鎖的高可用性,並無保證鎖的正確性。網絡

這個時候也許你會說,若是 Client 1 在提交任務以前去查詢一下鎖的持有者是不本身就能解決這個問題?架構

答案是否認的,FGC 會發生在任什麼時候候,若是 FGC 發生在查詢以後,同樣會有如上討論的問題。運維

那換一個沒有 GC 的編程語言?異步

答案仍是否認的, FGC 只是形成系統停頓的緣由之一,IO或者網絡的堵塞或波動均可能形成系統停頓。

Martin給出了一個解決的方案:

關於Redis RedLock算法的爭論

爲鎖增長一個 token-fencing。

  • 獲取鎖的時候,還須要獲取一個遞增的token,在上圖中 Client 1 還得到了一個 token=33的 fencing。
  • 發生了上文的 FGC 問題後,Client 獲取了 token=34 的鎖。
  • 在提交數據的時候,須要判斷token的大小,若是token 小於 上一次提交的 token 數據就會被拒絕。

咱們其實能夠理解這個 token-fencing 就是一個樂觀鎖,或者一個 CAS。

Martin 還指出了,RedLock 是一個 嚴重依賴系統時鐘 的分佈式系統。

仍是這個過時時間的小辮子。若是某個 Redis Master的系統時間發生了錯誤,形成了它持有的鎖提早過時被釋放。

  • Client 1 從 A、B、D、E五個節點中,獲取了 A、B、C三個節點獲取到鎖,咱們認爲他持有了鎖
  • 這個時候,因爲 B 的系統時間比別的系統走得快,B就會先於其餘兩個節點優先釋放鎖。
  • Clinet 2 能夠從 B、D、E三個節點獲取到鎖。在整個分佈式系統就形成 兩個 Client 同時持有鎖了。

這個時候 Martin 又提出了一個至關重要的關於分佈式系統的設計要點:

好的分佈式系統應當是異步的,且不能時間做爲安全保障的。由於在分佈式系統中有會程序暫停,網絡延遲,系統時間錯誤,這些因數都不能影響分佈式系統的安全性,只能影響系統的活性(liveness property)。換句話說,就是在極端狀況下, 分佈式系統頂多在有限的時間內不能給出結果,可是不能給出錯誤的結果 

因此總結一下 Martin 對 RedLock 的批評:

  • 對於提高效率的場景下,RedLock 過重。
  • 對於對正確性要求極高的場景下,RedLock 並不能保證正確性。

這個時候感受醍醐灌頂,簡直寫的太好了。

RedLock 的做者,同時也Redis 的做者對 Martin的文章也作了迴應,條理也是至關的清楚。

antirez 的迴應

antirez 看到了 Martin 的文章之後,就寫了一篇文章回應。劇情會不會反轉呢?

antirez 總結了 Martin 對 RedLock的指控:

  1. 分佈式的鎖具備一個自動釋放的功能。鎖的互斥性,只在過時時間以內有效,鎖過時釋放之後就會形成多個Client 持有鎖。
  2. RedLock 整個系統是創建在,一個在實際系統沒法保證的系統模型上的。在這個例子中就是系統假設時間是同步且可信的。

對於第一個問題:

antirez 洋洋灑灑的寫了不少,仔細看半天,也沒有解決我心中的疑問。回顧一下RedLock 獲取鎖的步驟:

  1. 獲取開始時間
  2. 去各個節點獲取鎖
  3. 再次獲取時間。
  4. 計算獲取鎖的時間,檢查獲取鎖的時間是否小於獲取鎖的時間。
  5. 持有鎖,該幹啥幹啥去

若是,程序在1-3步之間發生了阻塞,RedLock能夠感知到鎖已通過期,沒有問題。

若是,程序在第 4 步以後發生了阻塞?怎麼辦???

答案是,其餘 具備自動釋放鎖的分佈式鎖都沒辦解決這個問題 

對於第二個質疑:

antirez 認爲,首先在實際的系統中,從兩個方面來看:

  1. 系統暫停,網絡延遲。
  2. 系統的時間發生階躍。

對於第1個問題。上文已經提到了,RedLock作了一些微小的工做,可是沒辦法徹底避免。其餘帶有自動釋放的分佈式鎖也沒有辦法。

第2個問題,Martin認爲系統時間的階躍主要來自兩個方面:

  • 人爲修改。
  • 從NTP服務收到了一個跳躍時時鐘更新。

對於人爲修改,能說啥呢?人要搞破壞沒辦法避免。

NTP受到一個階躍時鐘更新,對於這個問題,須要經過運維來保證。須要將階躍的時間更新到 服務器 的時候,應當採起小步快跑的方式。屢次修改,每次更新時間儘可能小。

 

 

因此嚴格來講確實, RedLock創建在了 Time 是可信的模型上,理論上 Time 也是發生錯誤,可是在現實中,良好的運維和工程一些機制是能夠最大限度的保證 Time 可信。

最後, antirez 還打出了一個暴擊,既然 Martin 提出的系統使用 fecting token 保證數據的順序處理。還須要 RedLock,或者別的分佈式鎖幹啥??

回顧

每個系統設計都有本身的側重或者侷限。工程也不是完美的。在現實中工程中不存在完美的解決方案。咱們應當深刻了解其中的原理,瞭解解決方案的優缺點。明白選用方案的侷限性。是否能夠接受方案的侷限帶來的後果。

架構原本就是一門平衡的藝術。

簡單來講,單實例Redis能解決大部分的分佈式鎖需求。Redlock的引入意義不大,若是對可用性要求更高的話,使用其餘方案也許是更好的選擇。

相關文章
相關標籤/搜索