最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文詳解如何使用Redis實(shí)現(xiàn)分布式鎖

 更新時(shí)間:2022年09月06日 08:50:10   作者:程序員讀書(shū)???????  
這篇文章主要介紹了一文詳解如何使用Redis實(shí)現(xiàn)分布式鎖,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

1. 什么是分布式鎖

當(dāng)我們?cè)诰帉?xiě)多線程代碼的時(shí)候,不同的線程可能會(huì)發(fā)生資源的爭(zhēng)奪,為了避免資源爭(zhēng)奪造成的錯(cuò)誤,我們會(huì)對(duì)資源上鎖,只有獲得鎖的線程才能繼續(xù)往下執(zhí)行。

進(jìn)程中的鎖,本質(zhì)就是內(nèi)存中一個(gè)變量,當(dāng)一個(gè)線程執(zhí)行某個(gè)操作申請(qǐng)加鎖時(shí),如果能成功把代表鎖的變量值設(shè)置為1,則表示獲得了鎖,其他線程想要獲得鎖時(shí)會(huì)阻塞,而擁有鎖的線程執(zhí)行完操作后,再把鎖的值設(shè)置為0,則表示釋放了鎖。

上面我們說(shuō)的是在一臺(tái)服務(wù)器的進(jìn)程內(nèi)不同線程之間的鎖,這個(gè)鎖是放在內(nèi)存中的,而對(duì)于分布式應(yīng)用程序來(lái)說(shuō),不同的應(yīng)用(進(jìn)程或線程)部署在不同的服務(wù)器上,這樣就不能通過(guò)內(nèi)存中的變量來(lái)表示鎖。

即然在一臺(tái)服務(wù)器上可以通過(guò)內(nèi)存這塊共享的空間來(lái)表示鎖,那么對(duì)于分布式應(yīng)用程序來(lái)說(shuō),可以共享存儲(chǔ)系統(tǒng)來(lái)存儲(chǔ)一個(gè)共享鎖,這就是分布式鎖,而Redis作為內(nèi)存數(shù)據(jù)庫(kù),執(zhí)行非常快,很適合作為實(shí)現(xiàn)分布式鎖的共享存儲(chǔ)系統(tǒng)。

2. 使用Redis實(shí)現(xiàn)分布式鎖

對(duì)于一個(gè)鎖來(lái)說(shuō),其實(shí)只有兩個(gè)操作,加鎖和釋放鎖,下面我們看來(lái)看通過(guò)Redis要怎么實(shí)現(xiàn)?

2.1 加鎖

Redissetnx命令會(huì)判斷鍵值是否存在,如果存在則不做任何操作,并返回0,如果不存在,則創(chuàng)建并賦值,并返回1,因此我們可以執(zhí)行setnx為一個(gè)代表鎖鍵設(shè)置值,如果能設(shè)置成功,則表示獲得鎖,失敗則無(wú)法獲得鎖。

# 使用key為lock來(lái)表示一個(gè)鎖
setnx lock 1 

2.2 釋放鎖

當(dāng)執(zhí)行好操作之后,要釋放鎖的時(shí)候直接把Redis里的鍵值lock刪除就可以了,這樣其他進(jìn)程才能通過(guò)setnx命令重新設(shè)置并獲得該鎖。

# 釋放鎖
del lock

通過(guò)上面兩個(gè)命令,我們實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的分布式鎖,但這里就出現(xiàn)了一個(gè)問(wèn)題:如果一個(gè)進(jìn)程通過(guò)setnx命令加鎖之后,在執(zhí)行具體操作出錯(cuò)了,沒(méi)有辦法及時(shí)釋放鎖,那么其他進(jìn)程就無(wú)法獲得該鎖,系統(tǒng)便無(wú)法繼續(xù)往下執(zhí)行,解決這個(gè)問(wèn)題的辦法就是為鎖設(shè)置一個(gè)有效期,在這個(gè)有效期之后,自動(dòng)釋放鎖。

2.3 給鎖設(shè)置有效期

給鎖設(shè)置有效期非常簡(jiǎn)單,直接使用Redisexpire命令就可以了,如:

# 加鎖
setnx lock 1 
# 給鎖設(shè)置10s有效期
expire lock 10 

但是,現(xiàn)在又出現(xiàn)另一個(gè)問(wèn)題了,如果我們?cè)谠O(shè)置了鎖之后,執(zhí)行expire命令之前該進(jìn)程掛掉了,那么expire就沒(méi)有執(zhí)行成功,鎖一樣是沒(méi)有被釋放掉的,所以一定要保證上面兩個(gè)命令要一起執(zhí)行,怎么保證呢?

有兩個(gè)方法,一個(gè)是使用LUA語(yǔ)言編寫(xiě)的腳本,另一個(gè)是使用Redisset命令,set命令后面跟nx參數(shù)后,執(zhí)行的效果與setnx一致,且set命令可以跟ex參數(shù)來(lái)設(shè)置過(guò)期時(shí)間,所以我們可以使用set命令把setnxexpire兩個(gè)合并在一起,這樣就可以保證執(zhí)行的原子性了。

# 判斷是否鍵值是否存在,ex后面跟著的是鍵值的有效期,10s
set lock 1 nx ex 10 

解決了鎖的有效問(wèn)題,現(xiàn)在我們?cè)賮?lái)看另外一個(gè)問(wèn)題。

如上圖所示,現(xiàn)在有A,BC三個(gè)不同服務(wù)器上的進(jìn)程在執(zhí)行某個(gè)操作都需要獲得鎖,執(zhí)行后要釋放鎖。

現(xiàn)在的情況是進(jìn)程A執(zhí)行第2步時(shí)卡頓了(上面綠色區(qū)域所示),且時(shí)間超出了鎖有效期,所以進(jìn)程A設(shè)置的鎖自動(dòng)釋放了,這時(shí)候進(jìn)程B獲得了鎖,并開(kāi)始執(zhí)行操作,但由于進(jìn)程A只是卡頓了而已,所以會(huì)繼續(xù)執(zhí)行的時(shí)候,在第3步的時(shí)候會(huì)手動(dòng)釋放鎖,但是這個(gè)時(shí)候,鎖由線程B所擁有,也就是說(shuō)進(jìn)程A刪除的不是自己的鎖,而進(jìn)程B的鎖,這時(shí)候進(jìn)程B還沒(méi)執(zhí)行完,但鎖被釋放后,進(jìn)程C可以加鎖,也就是說(shuō)由于進(jìn)程A卡頓釋放錯(cuò)了鎖,導(dǎo)致進(jìn)程B和進(jìn)程C可以同時(shí)獲得鎖。

怎么避免這種情況呢?如何區(qū)分其他進(jìn)程的鎖,避免刪除其他進(jìn)程的鎖呢?答案就是每個(gè)進(jìn)程在加鎖的時(shí)候,給鎖設(shè)置一個(gè)唯一值,并在釋放鎖的時(shí)候,判斷是不是自己設(shè)置的鎖。

2.4 給鎖設(shè)置唯一值

給鎖設(shè)置唯一值的時(shí)候,一樣是使用set命令,唯一的不同是將鍵值1改為一個(gè)隨機(jī)生成的唯一值,比如uuid。

 # rand_uid表示唯一id
set lock rand_id nx ex 10

當(dāng)鎖里的值由進(jìn)程設(shè)置后,釋放鎖的時(shí)候,就需要判斷鎖是不是自己的,步驟如下:

  • 通過(guò)Redisget命令獲得鎖的值
  • 根據(jù)獲得的值,判斷鎖是不是自己設(shè)置的
  • 如果是,通過(guò)del命令釋放鎖。

此時(shí)我們看到,釋放鎖需要執(zhí)行三個(gè)操作,如果三個(gè)操作依次執(zhí)行的話(huà),是沒(méi)有辦法保證原子性的,比如進(jìn)程A在執(zhí)行到第2步后,準(zhǔn)備開(kāi)始執(zhí)行del命令時(shí),而鎖由時(shí)有效期到了,被自動(dòng)釋放了,并被其他服務(wù)器上的進(jìn)程B獲得鎖,但這時(shí)候線程A執(zhí)行del還是把線程B的鎖給刪掉了。

解決這個(gè)問(wèn)題的辦法就是保證上述三個(gè)操作執(zhí)行的原子性,即在執(zhí)行釋放鎖的三個(gè)操作中,其他進(jìn)程不可以獲得鎖,想要做到這一點(diǎn),需要使用到LUA腳本。

2.5 通過(guò)LUA腳本實(shí)現(xiàn)釋放鎖的原子性

Redis支持LUA腳本,LUA腳里的代碼執(zhí)行的時(shí)候,其他客戶(hù)端的請(qǐng)求不會(huì)被執(zhí)行,這樣可以保證原子性操作,所以我們可以使用下面腳本進(jìn)行鎖的釋放:

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

將上述腳本保存為腳本后,可以調(diào)用Redis客戶(hù)端命令redis-cli來(lái)執(zhí)行,如下:

# lock為key,rand_id表示key里保存的值
redis-cli --eval unlock.lua lock , rand_id 

3. 小結(jié)

無(wú)論是本地鎖還是分布式鎖,鎖的本質(zhì)就是一個(gè)共享的變量,只是在實(shí)現(xiàn)分布式鎖時(shí)候,把這個(gè)變量移到了Redis服務(wù)器所在的內(nèi)存中。

在上面實(shí)現(xiàn)分布式鎖的過(guò)程中我們碰到了以下幾個(gè)問(wèn)題:

  • 如何保證加鎖操作的原子性?
  • 如何保證進(jìn)程崩潰自動(dòng)釋放鎖?
  • 如何避免刪錯(cuò)其他進(jìn)程的鎖?
  • 如何保證釋放鎖操作的原子性?

在解決上述問(wèn)題的時(shí)候,我們也一步步完善一個(gè)可以在實(shí)際開(kāi)發(fā)中應(yīng)用的Redis分布式鎖。

到此這篇關(guān)于一文詳解如何使用Redis實(shí)現(xiàn)分布式鎖的文章就介紹到這了,更多相關(guān)Redis實(shí)現(xiàn)分布式鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis SETNX命令在Spring Cloud中的分布式鎖用法詳解

    Redis SETNX命令在Spring Cloud中的分布式鎖用法詳解

    在Spring Cloud項(xiàng)目中,使用Java和Redis結(jié)合實(shí)現(xiàn)的分布式鎖可以確保訂單的一致性和并發(fā)控制,通過(guò)合理使用鎖的粒度以及注意事項(xiàng),可以減少死鎖問(wèn)題并提高系統(tǒng)的并發(fā)性能,這篇文章主要介紹了Redis SETNX命令在Spring Cloud中的分布式鎖用法詳解,需要的朋友可以參考下
    2023-10-10
  • Redis哨兵模式實(shí)現(xiàn)一主二從三哨兵

    Redis哨兵模式實(shí)現(xiàn)一主二從三哨兵

    本文主要介紹了Redis哨兵模式實(shí)現(xiàn)一主二從三哨兵,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • SpringBoot整合Redis入門(mén)之緩存數(shù)據(jù)的方法

    SpringBoot整合Redis入門(mén)之緩存數(shù)據(jù)的方法

    Redis是一個(gè)開(kāi)源的使用ANSI C語(yǔ)言編寫(xiě)、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫(kù),并提供多種語(yǔ)言的API,下面通過(guò)本文給大家介紹下SpringBoot整合Redis入門(mén)之緩存數(shù)據(jù)的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2021-11-11
  • Redis中的數(shù)據(jù)過(guò)期策略詳解

    Redis中的數(shù)據(jù)過(guò)期策略詳解

    這篇文章主要介紹了Redis中的數(shù)據(jù)過(guò)期策略,文中通過(guò)示例代碼介紹的很詳細(xì),相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考借鑒價(jià)值,有需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-01-01
  • Redis的4種緩存模式分享

    Redis的4種緩存模式分享

    這篇文章主要介紹了Redis的4種緩存模式分享,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-07-07
  • redis鎖機(jī)制介紹與實(shí)例

    redis鎖機(jī)制介紹與實(shí)例

    今天小編就為大家分享一篇關(guān)于redis鎖機(jī)制介紹與實(shí)例,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • Reactor?WebFlux集成Redis處理緩存操作

    Reactor?WebFlux集成Redis處理緩存操作

    這篇文章主要為大家介紹了Reactor?WebFlux集成Redis處理緩存操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Redis的過(guò)期鍵刪除策略原理說(shuō)明

    Redis的過(guò)期鍵刪除策略原理說(shuō)明

    這篇文章主要介紹了Redis的過(guò)期鍵刪除策略原理說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Redisson分布式鎖解鎖異常問(wèn)題

    Redisson分布式鎖解鎖異常問(wèn)題

    文章主要描述了在使用Redisson進(jìn)行分布式鎖操作時(shí),遇到的`IllegalMonitorStateException`異常,通過(guò)分析報(bào)錯(cuò)信息,作者發(fā)現(xiàn)了問(wèn)題的根源在于線程嘗試解鎖但未按順序執(zhí)行,作者提出了兩種解決方案:在解鎖前增加判斷,確保線程已獲得鎖
    2024-12-12
  • 手動(dòng)實(shí)現(xiàn)Redis的LRU緩存機(jī)制示例詳解

    手動(dòng)實(shí)現(xiàn)Redis的LRU緩存機(jī)制示例詳解

    這篇文章主要介紹了手動(dòng)實(shí)現(xiàn)Redis的LRU緩存機(jī)制示例詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03

最新評(píng)論

石柱| 嘉义县| 桃园市| 育儿| 桑日县| 简阳市| 金阳县| 三都| 元阳县| 望城县| 荆州市| 平果县| 安阳市| 广灵县| 类乌齐县| 延津县| 广东省| 岗巴县| 德化县| 盘锦市| 玉田县| 吴堡县| 都昌县| 买车| 祁门县| 横山县| 罗源县| 澄城县| 昌图县| 虹口区| 南岸区| 张家川| 嵩明县| 泰顺县| 鄂尔多斯市| 巩留县| 会东县| 商城县| 苗栗县| 沙雅县| 桃园县|