1.基于Redis的分布式鎖到底安全嗎?
在服務(wù)器宕機(jī),或者網(wǎng)絡(luò)延時(shí)過高的時(shí)候,redis分布式鎖會出現(xiàn)不安全的情況。
情景1: 主從模式下
客戶端1在master中獲得了鎖,
在鎖同步到slave之前,master宕機(jī),還未來得及將鎖同步到slave
slave升級為master
客戶端2在新的master中獲取了鎖
情景2:網(wǎng)絡(luò)延時(shí)過長,客戶端與其他資源交互時(shí)間過長
客戶端1獲取鎖,因 網(wǎng)絡(luò)延時(shí),客戶端長時(shí)間阻塞 ,鎖過期,這時(shí)客戶端2獲取鎖,與此同時(shí)客戶端1的網(wǎng)絡(luò)恢復(fù)正常,這就導(dǎo)致兩個(gè)客戶端可同時(shí)訪問共享資源。
2. Redlock
基于上述情況,新的分布式鎖的算法Redlock
運(yùn)行Redlock算法的客戶端依次執(zhí)行下面各個(gè)步驟,來完成獲取鎖的操作:
- 獲取當(dāng)前時(shí)間(毫秒數(shù))。
- 按順序依次向N個(gè)Redis節(jié)點(diǎn)執(zhí)行獲取鎖的操作。這個(gè)獲取操作跟前面基于 單Redis節(jié)點(diǎn)的獲取鎖的過程相同,包含隨機(jī)字符串my_random_value,也包含過期時(shí)間(比如PX 30000,即鎖的有效時(shí)間)。為了保證在某個(gè)Redis節(jié)點(diǎn)不可用的時(shí)候算法能夠繼續(xù)運(yùn)行,這個(gè)獲取鎖的操作還有一個(gè)超時(shí)時(shí)間(time out),它要遠(yuǎn)小于鎖的有效時(shí)間(幾十毫秒量級)??蛻舳嗽谙蚰硞€(gè)Redis節(jié)點(diǎn)獲取鎖失敗以后,應(yīng)該立即嘗試下一個(gè)Redis節(jié)點(diǎn)。這里的失敗,應(yīng)該包含任何類型的失敗,比如該Redis節(jié)點(diǎn)不可用,或者該Redis節(jié)點(diǎn)上的鎖已經(jīng)被其它客戶端持有(注:Redlock原文中這里只提到了Redis節(jié)點(diǎn)不可用的情況,但也應(yīng)該包含其它的失敗情況)。
- 計(jì)算整個(gè)獲取鎖的過程總共消耗了多長時(shí)間,計(jì)算方法是用當(dāng)前時(shí)間減去第1步記錄的時(shí)間。如果客戶端從大多數(shù)Redis節(jié)點(diǎn)(>= N/2+1)成功獲取到了鎖,并且獲取鎖總共消耗的時(shí)間沒有超過鎖的有效時(shí)間(lock validity time),那么這時(shí)客戶端才認(rèn)為最終獲取鎖成功;否則,認(rèn)為最終獲取鎖失敗。
- 如果最終獲取鎖成功了,那么這個(gè)鎖的有效時(shí)間應(yīng)該重新計(jì)算,它等于最初的鎖的有效時(shí)間減去第3步計(jì)算出來的獲取鎖消耗的時(shí)間。
- 如果最終獲取鎖失敗了(可能由于獲取到鎖的Redis節(jié)點(diǎn)個(gè)數(shù)少于N/2+1,或者整個(gè)獲取鎖的過程消耗的時(shí)間超過了鎖的最初有效時(shí)間),那么客戶端應(yīng)該立即向所有Redis節(jié)點(diǎn)發(fā)起釋放鎖的操作(即前面介紹的Redis Lua腳本)。
三、Redlock存在的問題
由于N個(gè)Redis節(jié)點(diǎn)中的大多數(shù)能正常工作就能保證Redlock正常工作,因此理論上它的可用性更高。 我們前面討論的單Redis節(jié)點(diǎn)的分布式鎖在failover的時(shí)候鎖失效的問題,在Redlock中不存在了(解決了遺留問題1) ,但如果有節(jié)點(diǎn)發(fā)生崩潰重啟,還是會對鎖的安全性有影響的。具體的影響程度跟Redis對數(shù)據(jù)的持久化程度有關(guān)。
根據(jù)上述提出的算法, 當(dāng)N個(gè)節(jié)點(diǎn)中有一個(gè)節(jié)點(diǎn)宕機(jī), 仍然存在鎖的安全性問題。具體的影響跟redis的持久化程度有關(guān)
假設(shè)一共有5個(gè)Redis節(jié)點(diǎn):A, B, C, D, E。設(shè)想發(fā)生了如下的事件序列:
客戶端1成功鎖住了A, B, C,獲取鎖成功(但D和E沒有鎖住)。
節(jié)點(diǎn)C崩潰重啟了,但客戶端1在C上加的鎖沒有持久化下來,丟失了。
節(jié)點(diǎn)C重啟后,客戶端2鎖住了C, D, E,獲取鎖成功。
這樣,客戶端1和客戶端2同時(shí)獲得了鎖(針對同一資源)。
其它問題
1、客戶端長時(shí)間阻塞,導(dǎo)致獲得的鎖釋放,訪問的共享資源不受保護(hù)的問題。
2、在Redlock的算法中,我們可以看到第3步,當(dāng)獲取鎖耗時(shí)太多,留給客戶端的訪問共享資源的時(shí)間很短,這種情況若來不及操作,是不是要釋放鎖呢?且到底剩下多少時(shí)間才算短?這又是一個(gè)選擇難題。
3、Redlock算法對時(shí)鐘依賴性太強(qiáng), 若N個(gè)節(jié)點(diǎn)中的某個(gè)節(jié)點(diǎn)發(fā)生 時(shí)間跳躍 ,也可能會引此而引發(fā)鎖安全性問題。