欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文詳解如何使用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ě)多線(xiàn)程代碼的時(shí)候,不同的線(xiàn)程可能會(huì)發(fā)生資源的爭(zhēng)奪,為了避免資源爭(zhēng)奪造成的錯(cuò)誤,我們會(huì)對(duì)資源上鎖,只有獲得鎖的線(xiàn)程才能繼續(xù)往下執(zhí)行。

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

上面我們說(shuō)的是在一臺(tái)服務(wù)器的進(jìn)程內(nèi)不同線(xiàn)程之間的鎖,這個(gè)鎖是放在內(nèi)存中的,而對(duì)于分布式應(yīng)用程序來(lái)說(shuō),不同的應(yīng)用(進(jìn)程或線(xià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í)行非??欤苓m合作為實(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,B,C三個(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í)候,鎖由線(xiàn)程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í)候線(xiàn)程A執(zhí)行del還是把線(xiàn)程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)文章

  • windows平臺(tái)安裝部署Redis

    windows平臺(tái)安裝部署Redis

    Redis是一個(gè)開(kāi)源、跨平臺(tái)的數(shù)據(jù)庫(kù),因此Redis數(shù)據(jù)庫(kù)可以運(yùn)行在Windows、Linux、Mac OS和BSD等多個(gè)平臺(tái)上,本文主要介紹了windows平臺(tái)安裝部署Redis,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • 詳解如何清理redis集群的所有數(shù)據(jù)

    詳解如何清理redis集群的所有數(shù)據(jù)

    這篇文章主要介紹了詳解如何清理redis集群的所有數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 從零搭建SpringBoot2.X整合Redis框架的詳細(xì)教程

    從零搭建SpringBoot2.X整合Redis框架的詳細(xì)教程

    這篇文章主要介紹了從零搭建SpringBoot2.X整合Redis框架的詳細(xì)教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Redis 命令的詳解及簡(jiǎn)單實(shí)例

    Redis 命令的詳解及簡(jiǎn)單實(shí)例

    這篇文章主要介紹了Redis 命令的詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,這里提供基礎(chǔ)語(yǔ)法及使用實(shí)例,需要的朋友可以參考下
    2017-08-08
  • Redis server 主從復(fù)制配置實(shí)現(xiàn)

    Redis server 主從復(fù)制配置實(shí)現(xiàn)

    從復(fù)制是指將一個(gè)Redis服務(wù)器的數(shù)據(jù)復(fù)制到其他Redis服務(wù)器的過(guò)程,本文主要介紹了Redis server 主從復(fù)制配置實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • NestJS+Redis實(shí)現(xiàn)緩存步驟詳解

    NestJS+Redis實(shí)現(xiàn)緩存步驟詳解

    這篇文章主要介紹了NestJS+Redis實(shí)現(xiàn)緩存,本文分步驟給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • Redis通過(guò)scan查找不過(guò)期的 key(方法詳解)

    Redis通過(guò)scan查找不過(guò)期的 key(方法詳解)

    SCAN 命令是一個(gè)基于游標(biāo)的迭代器,每次被調(diào)用之后, 都會(huì)向用戶(hù)返回一個(gè)新的游標(biāo), 用戶(hù)在下次迭代時(shí)需要使用這個(gè)新游標(biāo)作為 SCAN 命令的游標(biāo)參數(shù), 以此來(lái)延續(xù)之前的迭代過(guò)程,對(duì)Redis scan 查找 key相關(guān)知識(shí)感興趣的朋友一起看看吧
    2021-08-08
  • 生產(chǎn)redisson延時(shí)隊(duì)列不消費(fèi)問(wèn)題排查解決

    生產(chǎn)redisson延時(shí)隊(duì)列不消費(fèi)問(wèn)題排查解決

    這篇文章主要為大家介紹了生產(chǎn)redisson延時(shí)隊(duì)列不消費(fèi)問(wèn)題排查解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 通過(guò) Redis 實(shí)現(xiàn) RPC 遠(yuǎn)程方法調(diào)用(支持多種編程語(yǔ)言)

    通過(guò) Redis 實(shí)現(xiàn) RPC 遠(yuǎn)程方法調(diào)用(支持多種編程語(yǔ)言)

    這篇文章主要介紹了通過(guò) Redis 實(shí)現(xiàn) RPC 遠(yuǎn)程方法調(diào)用,支持多種編程語(yǔ)言,本文就以Ruby和Python為例,給出了實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2014-09-09
  • Unable?to?connect?to?Redis無(wú)法連接到Redis解決的全過(guò)程

    Unable?to?connect?to?Redis無(wú)法連接到Redis解決的全過(guò)程

    這篇文章主要給大家介紹了關(guān)于Unable?to?connect?to?Redis無(wú)法連接到Redis解決的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼將解決的過(guò)程介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03

最新評(píng)論