【redis】分布式鎖的實(shí)現(xiàn)

setnx

redis 分布式鎖使用非常廣泛的,來實(shí)現(xiàn)對一些共享資源進(jìn)行互斥訪問。

一般使用setnx(set if not exists) 來搶占,del 來釋放。

 setnx lock 1
... do something ...
del lock

但是這個(gè)流程有問題,如果del 調(diào)用失敗或者異常導(dǎo)致del 沒有調(diào)用,就會(huì)陷入死鎖,導(dǎo)致鎖永遠(yuǎn)不能釋放??梢韵氲降囊粋€(gè)解決方案就是我們給鎖加一個(gè)過期時(shí)間,如下:

 setnx lock 1
expire lock 5
... do something ...
del lock

但是上述流程還是有問題,如果expire 調(diào)用失敗,還是會(huì)陷入死鎖。于是我們想到下面代碼程序校驗(yàn)的方案來解決可能的死鎖問題:

current_ts = time()
lock_ts = redis->get('lock')
if (!lock_ts || current_ts - lock_ts > 5) {
    redis->set(lock, current_ts)
    redis->expire(lock, 5)
    ... do something ...
    del lock
} else {
  return false
}

但是上述方案還是有問題的,原因就在于搶占資源不是原子操作的,當(dāng)我們的程序訪問并發(fā)比較高的時(shí)候,會(huì)有多個(gè)訪問同時(shí)搶占到鎖,不能保證互斥性。

那怎么解決呢? 好在Redis 2.8 版本之后,redis 的set 執(zhí)行增加了擴(kuò)展參數(shù),使setnx 和expire 可以一起執(zhí)行,從而解決了上述難題。

SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]

set lock 1 ex 5 nx 
... do something ...
del lock

del誤刪

上述方案還是會(huì)存在誤刪問題:假如線程A獲得鎖并且設(shè)置超時(shí)時(shí)間為30秒,某種原因?qū)е戮€程A執(zhí)行很慢,超過30秒后線程A鎖自動(dòng)過期,釋放了鎖,線程B獲了鎖。隨后線程A執(zhí)行完成,del刪除鎖,但線程B還未執(zhí)行完成,實(shí)際上線程A刪除的是線程B的鎖。

解決方案就是通過lua腳本實(shí)現(xiàn)一個(gè)樂觀鎖:
線程在加鎖的時(shí)候,可以給鎖加一個(gè)版本號或者隨機(jī)數(shù)來區(qū)分。

SET lock rand_value EX 300 NX

del鎖之前先做判斷,通過lua腳本來保證判斷和del 兩個(gè)操作的原子性。

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

其他問題

  1. 前面這個(gè)算法中出現(xiàn)的鎖的有效時(shí)間(lock validity time),設(shè)置成多少合適呢?如果設(shè)置太短的話,鎖就有可能在客戶端完成對于共享資源的訪問之前過期,從而失去保護(hù);如果設(shè)置太長的話,一旦某個(gè)持有鎖的客戶端釋放鎖失敗,那么就會(huì)導(dǎo)致所有其它客戶端都無法獲取鎖,從而長時(shí)間內(nèi)無法正常工作??磥碚媸莻€(gè)兩難的問題。

  2. 假如Redis節(jié)點(diǎn)宕機(jī)了,那么所有客戶端就都無法獲得鎖了,服務(wù)變得不可用。為了提高可用性,我們可以給這個(gè)Redis節(jié)點(diǎn)掛一個(gè)Slave,當(dāng)Master節(jié)點(diǎn)不可用的時(shí)候,系統(tǒng)自動(dòng)切到Slave上(failover)。但由于Redis的主從復(fù)制(replication)是異步的,這可能導(dǎo)致在failover過程中喪失鎖的安全性。這是基于單Redis節(jié)點(diǎn)的分布式鎖無法解決的,而Redlock算法就是為了解決這個(gè)問題提出的,是基于多個(gè)Redis節(jié)點(diǎn)(都是Master)的一種實(shí)現(xiàn)。詳情可以看下官網(wǎng)介紹:https://redis.io/topics/distlock ,也可以參考一下這篇blog的介紹:http://zhangtielei.com/posts/blog-redlock-reasoning.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容