redis 分布式鎖苛蒲, 你真的懂么

SETNX命令簡(jiǎn)介

命令格式

SETNX key value

將 key 的值設(shè)為 value捉捅,當(dāng)且僅當(dāng) key 不存在。

若給定的 key 已經(jīng)存在寄月,則 SETNX 不做任何動(dòng)作无牵。

返回整數(shù)漾肮,具體為

- 1克懊,當(dāng) key 的值被設(shè)置

- 0谭溉,當(dāng) key 的值沒(méi)被設(shè)置

使用SETNX實(shí)現(xiàn)分布式鎖

多個(gè)進(jìn)程執(zhí)行以下Redis命令:

SETNX lock.lock <current time + timeout +1 > ? //其中1是cover鎖獲取時(shí)間

如果 SETNX 返回1扮念,說(shuō)明該進(jìn)程獲得鎖柜与,SETNX將鍵 lock.lock 的值設(shè)置為鎖的超時(shí)時(shí)間(當(dāng)前時(shí)間 + 鎖的有效時(shí)間)弄匕。

如果 SETNX 返回0沽瞭,說(shuō)明其他進(jìn)程已經(jīng)獲得了鎖驹溃,進(jìn)程不能進(jìn)入臨界區(qū)。進(jìn)程可以在一個(gè)循環(huán)中不斷地嘗試 SETNX 操作,以獲得鎖傍药。

解決死鎖

1. 如果進(jìn)程獲得鎖后拐辽,斷開(kāi)了與 Redis 的連接(可能是進(jìn)程掛掉拣挪,或者網(wǎng)絡(luò)中斷),如果沒(méi)有有效的釋放鎖的機(jī)制俱诸,那么其他進(jìn)程都會(huì)處于一直等待的狀態(tài)菠劝,即出現(xiàn)“死鎖”。

2. 在使用 SETNX 獲得鎖時(shí)睁搭,我們將鍵 lock.lock 的值設(shè)置為鎖的有效時(shí)間赶诊,進(jìn)程獲得鎖后,其他進(jìn)程還會(huì)不斷的檢測(cè)鎖是否已超時(shí)园骆,如果超時(shí)舔痪,那么等待的進(jìn)程也將有機(jī)會(huì)獲得鎖。當(dāng)前進(jìn)程需要在超時(shí)時(shí)退出锌唾,否則超時(shí)后锄码,其他進(jìn)程有可能拿到鎖導(dǎo)致多個(gè)進(jìn)程同時(shí)拿到鎖。

3. 鎖超時(shí)時(shí)晌涕,我們不能簡(jiǎn)單地使用 DEL 命令刪除鍵 lock.lock 以釋放鎖重窟。考慮以下情況,進(jìn)程P1已經(jīng)首先獲得了鎖 lock.lock知给,然后進(jìn)程P1掛掉了。進(jìn)程P2,P3正在不斷地檢測(cè)鎖是否已釋放或者已超時(shí)花墩,執(zhí)行流程如下:

P2和P3進(jìn)程讀取鍵 lock.lock 的值,檢測(cè)鎖是否已超時(shí)(通過(guò)比較當(dāng)前時(shí)間和鍵 lock.lock 的值來(lái)判斷是否超時(shí))武氓,P2和P3進(jìn)程發(fā)現(xiàn)鎖 lock.lock 已超時(shí)弱睦,P2執(zhí)行 DEL lock.lock命令况木,P2執(zhí)行 SETNX lock.lock命令奔垦,并返回1,即P2獲得鎖。P3執(zhí)行 DEL lock.lock命令將P2剛剛設(shè)置的鍵 lock.lock 刪除(這步是由于P3剛才已檢測(cè)到鎖已超時(shí))鸯旁。P3執(zhí)行 SETNX lock.lock命令残炮,并返回1楷怒,即P3獲得鎖。P2和P3同時(shí)獲得了鎖。

從上面的情況可以得知,在檢測(cè)到鎖超時(shí)后,進(jìn)程不能直接簡(jiǎn)單地執(zhí)行 DEL 刪除鍵的操作以獲得鎖芹啥。

為了解決上述算法可能出現(xiàn)的多個(gè)進(jìn)程同時(shí)獲得鎖的問(wèn)題傀履,我們?cè)賮?lái)看以下的算法絮宁。

我們同樣假設(shè)進(jìn)程P1已經(jīng)首先獲得了鎖 lock.lock,然后進(jìn)程P1掛掉了。接下來(lái)的情況:

進(jìn)程P4執(zhí)行 SETNX lock.lock 以嘗試獲取鎖

由于進(jìn)程P1已獲得了鎖泪蔫,所以P4執(zhí)行 SETNX lock.lock 返回0,即獲取鎖失敗

P4執(zhí)行 GET lock.lock 來(lái)檢測(cè)鎖是否已超時(shí),如果沒(méi)超時(shí)朽合,則等待一段時(shí)間休讳,再次檢測(cè)

如果P4檢測(cè)到鎖已超時(shí),即當(dāng)前的時(shí)間大于鍵 lock.lock 的值尚骄,P4會(huì)執(zhí)行以下操作

GETSET lock.lock

由于 GETSET 操作在設(shè)置鍵的值的同時(shí)需五,還會(huì)返回鍵的舊值泽示,通過(guò)比較鍵 lock.lock 的舊值是否小于當(dāng)前時(shí)間械筛,可以判斷進(jìn)程是否已獲得鎖

假如另一個(gè)進(jìn)程P5也檢測(cè)到鎖已超時(shí),并在P4之前執(zhí)行了 GETSET 操作闯狱,那么P4的 GETSET 操作返回的是一個(gè)大于當(dāng)前時(shí)間的時(shí)間戳,這樣P4就不會(huì)獲得鎖而繼續(xù)等待吹截。

//實(shí)例代碼

LOCK_TIMEOUT =3

lock =0

lock_timeout =0

lock_key ='lock.lock'# 獲取鎖

while lock !=1:

now =int(time.time())

lock_timeout = now + LOCK_TIMEOUT +1

lock = redis_client.setnx(lock_key, lock_timeout)

if lock ==1 or (now >int(redis_client.get(lock_key))) and now > int(redis_client.getset(lock_key, lock_timeout)): ? //解決當(dāng)鎖超時(shí)時(shí)媒抠,兩個(gè)進(jìn)程同時(shí)判斷鎖可以獲取阀趴,只能其中一個(gè)可以設(shè)置成功

break

else:time.sleep(0.001)

# 已獲得鎖

do_job()

# 釋放鎖

now =int(time.time())

if now < lock_timeout:

redis_client.delete(lock_key)

有很多已經(jīng)實(shí)現(xiàn)好的基于redis的分布式鎖的封裝检碗,詳細(xì)見(jiàn) https://redis.io/topics/distlock

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末戈轿,一起剝皮案震驚了整個(gè)濱河市解虱,隨后出現(xiàn)的幾起案子漆撞,更是在濱河造成了極大的恐慌殴泰,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浮驳,死亡現(xiàn)場(chǎng)離奇詭異悍汛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)至会,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)离咐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人奉件,你說(shuō)我怎么就攤上這事宵蛀。” “怎么了县貌?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵术陶,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我煤痕,道長(zhǎng)梧宫,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任摆碉,我火速辦了婚禮祟敛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘兆解。我一直安慰自己馆铁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布锅睛。 她就那樣靜靜地躺著埠巨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪现拒。 梳的紋絲不亂的頭發(fā)上辣垒,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音印蔬,去河邊找鬼勋桶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的例驹。 我是一名探鬼主播捐韩,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鹃锈!你這毒婦竟也來(lái)了荤胁?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤屎债,失蹤者是張志新(化名)和其女友劉穎仅政,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體盆驹,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡圆丹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了躯喇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片运褪。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖玖瘸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情檀咙,我是刑警寧澤雅倒,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站弧可,受9級(jí)特大地震影響蔑匣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜棕诵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一裁良、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧校套,春花似錦价脾、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至妹孙,卻和暖如春秋柄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蠢正。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工骇笔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓笨触,卻偏偏與公主長(zhǎng)得像懦傍,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子旭旭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 分布式鎖的解決方式 基于數(shù)據(jù)庫(kù)表做樂(lè)觀鎖谎脯,用于分布式鎖。(適用于小并發(fā)) 使用memcached的add()方法持寄,...
    xiaolyuh閱讀 15,498評(píng)論 6 17
  • 一源梭、分布式鎖的作用: redis寫(xiě)入時(shí)不帶鎖定功能,為防止多個(gè)進(jìn)程同時(shí)進(jìn)行一個(gè)操作稍味,出現(xiàn)意想不到的結(jié)果废麻,so......
    魔法師_閱讀 2,053評(píng)論 0 6
  • 目前實(shí)現(xiàn)分布式鎖的方式主要有數(shù)據(jù)庫(kù)、Redis和Zookeeper三種模庐,本文主要闡述利用Redis的相關(guān)命令來(lái)實(shí)現(xiàn)...
    Aldeo閱讀 2,072評(píng)論 0 6
  • 【楔子】 講述這些事情需要冷靜烛愧,還需要良心帽衙,才能不讓它們淪為談資脂凶。 要冰涼,冰涼是結(jié)晶的憤怒砌创。 他們千萬(wàn)不能被忘記...
    亦然無(wú)茶閱讀 3,245評(píng)論 0 4
  • 給草原鋪一條路 告訴行人 路上是你的旅途 草原是我的自由 在沙漠里種一棵樹(shù) 告訴行人 乘涼是你的需要 陽(yáng)光是我的生命
    4f788f2cd2fd閱讀 207評(píng)論 2 2