中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

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

這篇文章主要介紹了使用redis如何實(shí)現(xiàn)分布式鎖的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇使用Redis如何實(shí)現(xiàn)分布式鎖文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。

創(chuàng)新互聯(lián)專注于企業(yè)全網(wǎng)營(yíng)銷推廣、網(wǎng)站重做改版、武陟網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5響應(yīng)式網(wǎng)站成都商城網(wǎng)站開(kāi)發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為武陟等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。

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,則表示釋放了鎖。

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

上面我們說(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í)行非??欤苓m合作為實(shí)現(xiàn)分布式鎖的共享存儲(chǔ)系統(tǒng)。

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

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)題。

使用Redis如何實(shí)現(xià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í)行的話,是沒(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í)候,其他客戶端的請(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客戶端命令redis-cli來(lái)執(zhí)行,如下:

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

關(guān)于“使用Redis如何實(shí)現(xiàn)分布式鎖”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“使用Redis如何實(shí)現(xiàn)分布式鎖”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

當(dāng)前題目:使用Redis如何實(shí)現(xiàn)分布式鎖
文章出自:http://www.rwnh.cn/article38/jipisp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名、網(wǎng)站設(shè)計(jì)、做網(wǎng)站、網(wǎng)站設(shè)計(jì)公司、網(wǎng)站內(nèi)鏈建站公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)
萝北县| 安新县| 海口市| 葫芦岛市| 淮南市| 偃师市| 湘阴县| 曲周县| 临泽县| 夏津县| 松阳县| 喜德县| 齐河县| 武山县| 定陶县| 苏尼特左旗| 天长市| 阜阳市| 昌黎县| 新余市| 普安县| 伊宁市| 黄大仙区| 兰西县| 邮箱| 霞浦县| 安阳县| 介休市| 突泉县| 新蔡县| 塔城市| 犍为县| 宽城| 海城市| 五河县| 迁西县| 偃师市| 临夏县| 安达市| 滦平县| 江川县|