亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

1. 什么是分布式鎖

當我們在編寫多線程代碼的時候,不同的線程可能會發(fā)生資源的爭奪,為了避免資源爭奪造成的錯誤,我們會對資源上鎖,只有獲得鎖的線程才能繼續(xù)往下執(zhí)行。

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

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

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

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

對于一個鎖來說,其實只有兩個操作,加鎖和釋放鎖,下面我們看來看通過Redis要怎么實現(xiàn)?

2.1 加鎖

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

# 使用key為lock來表示一個鎖
setnx lock 1 

2.2 釋放鎖

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

# 釋放鎖
del lock

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

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

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

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

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

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

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

解決了鎖的有效問題,現(xiàn)在我們再來看另外一個問題。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3. 小結(jié)

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

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

  • 如何保證加鎖操作的原子性?
  • 如何保證進程崩潰自動釋放鎖?
  • 如何避免刪錯其他進程的鎖?
  • 如何保證釋放鎖操作的原子性?

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

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

相關(guān)文章

  • windows平臺安裝部署Redis

    windows平臺安裝部署Redis

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

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

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

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

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

    Redis 命令的詳解及簡單實例

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

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

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

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

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

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

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

    生產(chǎn)redisson延時隊列不消費問題排查解決

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

    通過 Redis 實現(xiàn) RPC 遠程方法調(diào)用(支持多種編程語言)

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

    Unable?to?connect?to?Redis無法連接到Redis解決的全過程

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

最新評論