討論的問題:Redis 主從架構鎖失效(丟失)
1.背景描述
當主節點掛掉時,從節點會取而代之,但是客戶端卻沒有明顯感知。比如,原先第一個客戶端在主節點中成功申請了一把鎖,但是這把鎖還沒來得及同步到從節點,主節點突然掛掉了,然後從節點變成了主節點,這個新的主節點內部沒有這個鎖,所以當另一個客戶端傳送請求加鎖時,立即就批准了。這樣就會導致系統中同樣一把鎖被兩個客戶端同時持有,不安全性由此產生。
問題示意圖如下:
即使在Sentinel叢集下,此問題依然存在。
此問題在主從failover時才會發生,並且持續時間會很短,很多時候,對業務無明顯影響。
2. Redlock方案 Redlock實現原理
Redlock方案,需要多個Redis示例,這些示例之間相互獨立,沒有主從關係。通很多分散式演算法一樣,Redlock也使用“大多數機制”。
3.redlock-py----Realock演算法
import redlock addrs = [{ "host" : "localhost", "port" : 6379, "db" : 0 }, { "host" : "localhost", "port" : 6479, "db" : 0 }, { "host" : "localhost", "port" : 6579, "db" : 0 }] dlm = redlock.Redlock(addrs) sucess = dlm.lock("user-lck", 5000) if sucess: print 'lock sucess' dlm.unlock('user-lck') else: print 'lock failed'
加鎖時,它會向過半節點傳送set(key, value, nx=True, ex=xxx) 指令,只要過半節點set成功,就認為加鎖成功。釋放鎖時,需要向所有節點傳送del指令。
生產過程,還需要考慮出錯重試、時鐘漂移等細節問題。
4.壞處
(1)需要多臺Redis例項;
(2)因為Redlock需要向多個節點進行讀寫,意味著其相比單例項Redis的效能會下降。
特別是,當某一個節點掛掉,其成功寫入的返回時間明顯加大了。這是要特別消失程式對寫入redis超時時間的設定。(即redis還在寫入,但是redis客戶端已經認為寫入超時了)。
(3)極端情況,Redis故障或重啟,可能導致鎖丟失。
例如,Redis例項 其將資料fsync到磁碟的策略為【appendfsync everysec 即每秒fsync一次】,即在故障時,可能會丟失1秒鐘資料。
此時有A例項;B例項;C例項。
client請求,將資料寫入到了A例項和B例項了,C未寫入,並且A已經fsync磁碟了,B尚未fsync到磁碟。但是很不巧,B故障了,或重啟了,那麼B的資料丟失了。
這個時候,如果有新的請求,那麼B和C可能接收-設定同樣的key,這時候,對B而言,就像前面的key沒有出現過一樣,它忘記了。此時就可能出現“超賣”的問題。
當然,在【appendfsync always: 每次有新命令追加到AOF檔案時,就執行一次fsync】,就不會出現重啟,丟命令了。但是安全程式碼的成本就是慢和高消耗。
學習參閱宣告
《Redis深度歷險--核心原理與應用實踐》