如何使用redis實現(xiàn)分布式鎖_第1頁
如何使用redis實現(xiàn)分布式鎖_第2頁
如何使用redis實現(xiàn)分布式鎖_第3頁
如何使用redis實現(xiàn)分布式鎖_第4頁
如何使用redis實現(xiàn)分布式鎖_第5頁
已閱讀5頁,還剩9頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

30|如何使用Redis 進(jìn)入課上節(jié)課,我提到,在應(yīng)對并發(fā)問題時,除了原子操作,Redis客戶端還可以通過加鎖的方但是,Redis屬于分布式系統(tǒng),當(dāng)有多個客戶端需要爭搶鎖時,須要保證,這把鎖不能是某個客戶端本地的鎖。否則的話,其它客戶端是無法這把鎖的,當(dāng)然也就不能保存在一個共享系統(tǒng)中的,可以被多個客戶端共享和獲取。Redis本身可以被多個客戶端共享,正好就是一個共享系統(tǒng),可以用來保存分布式鎖。而且Redis的讀寫性能高,可以應(yīng)對高并發(fā)的鎖操作場景。所以,這節(jié)課,我就來和你聊聊如何基于Redis實現(xiàn)分布式鎖。我們?nèi)粘T趯懗绦虻臅r候,經(jīng)常會用到單機上的鎖,你應(yīng)該也比較熟悉了。而分布式鎖和單機上的鎖既有相似性,但也因為分布式鎖是用在分布式場景中,所以又具有一些特殊的要求。變量值為0時,表示沒有線程獲取鎖;變量值為1我們通常說的線程調(diào)用加鎖和釋放鎖的操作,到底是啥意思呢?我來解釋一下。實際上,一個線程調(diào)用加鎖操作,其實就是檢查鎖變量值是否為0。如果是0,就把鎖的變量值設(shè)置為1,表示獲取到鎖,如果不是0,就返回錯誤信息,表示加鎖失敗,已經(jīng)有別的線程獲取到鎖了。而一個線程調(diào)用釋放鎖操作,其實就是將鎖變量的值置為0,以便其它線程可以來獲取鎖。我用一段代碼來展示下加鎖和釋放鎖的操作,其中,lock為鎖變量。iflock==lock=returnreturn7lock=return12變量值來判斷能否加鎖成功;釋放鎖時需要把鎖變量值設(shè)置為0,表明客戶端不再持有但是,和線程在單機上操作鎖不同的是,在分布式場景下,鎖變量需要由一個共享系統(tǒng)來,,多個客戶端才可以通過共享系統(tǒng)來鎖變量。相應(yīng)的,加鎖和釋放鎖的操作就變成了、判斷和設(shè)置共享系統(tǒng)中的鎖變量值。要求二:共享系統(tǒng)保存了鎖變量,如果共享系統(tǒng)發(fā)生故障或宕機,那么客戶端也就無法進(jìn)行鎖操作了。在實現(xiàn)分布式鎖時,我們需要考慮保證共享系統(tǒng)的可靠性,進(jìn)而保證鎖的可靠性。好了,知道了具體的要求,接下來,我們就來學(xué)習(xí)下Redis是怎么實現(xiàn)分布式鎖的。其實,可以基于單個Redis節(jié)點來實現(xiàn),也可以使用多個Redis節(jié)點實現(xiàn)。在這兩種情況下,鎖的可靠性是不一樣的。我們先來看基于單個Redis節(jié)點的實現(xiàn)方法。Redis作為分布式鎖實現(xiàn)過程中的共享系統(tǒng),Reis可以使用鍵值對來保存鎖變量,再接收和處理不同客戶端發(fā)送的加鎖和釋放鎖的操作請求。那么,鍵值對的鍵和值具體是怎么定的呢?我們要賦予鎖變量一個變量名,把這個變量名作為鍵值對的鍵,而鎖變量的值,則是鍵值對的值,這樣一來,Reis就能保存鎖變量了,客戶端也就可以通過Reis令操作來實現(xiàn)鎖操作。為了幫助你理解,我畫了一張,它展示Redis使用鍵值對保存鎖變量,以及兩個客戶可以看到,Redislock_key:0lock_key,也是鎖變量的名稱,鎖變量的初始值是0。ACRedis端A和C同時把加鎖請求發(fā)給了Redis,Redis也會串行處理它們的請求。我們假設(shè)Redis先處理客戶端A的請求,lock_key的值,發(fā)現(xiàn)lock_key為0,所以,Redis就把lock_key的value置為1,表示已經(jīng)加鎖了。緊接著,Redis處理客戶端C,Redislock_key1了,所以就返回加鎖失敗的信息。為0。我還是借助一張來解釋一下。這張展示了客戶端A請求釋放鎖的過程。當(dāng)客戶端A持有鎖時,鎖變量lock_key的值為1??蛻舳薃執(zhí)行釋放鎖操作后,Redis將lock_key的值置為0,表明已經(jīng)沒有客戶端持有鎖了。因為加鎖包含了三個操作(鎖變量、判斷鎖變量值以及把鎖變量值設(shè)置為1),而這Redis命令操作和使用Lua。那么,在分布式加鎖場景下,該怎么應(yīng)用這兩個方法呢?首先是SETNX命令,它用于設(shè)置鍵值對的值。具體來說,就是這個命令在執(zhí)行時會判斷鍵舉個例子,如果執(zhí)行下面令時,key不存在,那么key會被創(chuàng)建,并且值會被設(shè)置1SETNXkey對于釋放鎖操作來說,我們可以在執(zhí)行完業(yè)務(wù)邏輯后,使用DEL命令刪除鎖變量。不過,你不用擔(dān)心鎖變量被刪除后,其他客戶端無法請求加鎖了。因為SETNX命令在執(zhí)行時,如果要設(shè)置的鍵值對(也就是鎖變量)不存在,SETNX所以,釋放鎖之后,再有客戶端請求加鎖時,SETNX命令會創(chuàng)建保存鎖變量的鍵值總結(jié)來說,我們就可以用SETNX和DEL命令組合來實現(xiàn)加鎖和釋放鎖操作。下面的偽代//SETNXlock_key//DO//DELSETNX和DEL第一個風(fēng)險是,假如某個客戶端在執(zhí)行了SETX命令、加鎖之后,緊接著卻在操作共享數(shù)據(jù)時發(fā)生了異常,結(jié)果一直沒有執(zhí)行最后的DEL命令釋放鎖。因此,鎖就一直被這個客戶端持有,其它客戶端無法拿到鎖,也無法共享數(shù)據(jù)和執(zhí)行后續(xù)操作,這會給業(yè)務(wù)應(yīng)用帶來影響。有鎖的客戶端發(fā)生了異常,無法主動地釋放鎖,Redis我們再來看第二個風(fēng)險。如果客戶端A執(zhí)行了SETNX命令加鎖后,假設(shè)客戶端B執(zhí)行了DEL命令釋放鎖,此時,客戶端A的鎖就被誤釋放了。如果客戶端C正好也在申請加鎖,就可以成功獲得鎖,進(jìn)而開始操作共享數(shù)據(jù)。這樣一來,客戶端A和C同時在對共享數(shù)據(jù)為了應(yīng)對這個問題,我們需要能區(qū)分來自不同客戶端的鎖操作,具體咋做呢?其實,我們在使用SETX命令進(jìn)行加鎖的方法中,我們通過把鎖變量值設(shè)置為1或0,表示是否加鎖成功。1和0只有兩種狀態(tài),無法表示究竟是哪個客戶端進(jìn)行的鎖操作。所以,我們在加鎖操作時,可以讓每個客戶端給鎖變量設(shè)置一個唯一值,這里的唯一值就可以用來標(biāo)識當(dāng)前操作的客戶端。在釋放鎖操作時,客戶端需要判斷,當(dāng)前鎖變量的值是否和自己的唯一標(biāo)識相等,只有在相等的情況下,才能釋放鎖。這樣一來,就不會出現(xiàn)誤釋放鎖的問題Redis在查看具體的代碼前,我要先帶你學(xué)習(xí)下Redis的SET命令。我們剛剛在說SETNX命令的時候提到,對于不存在的鍵值對,它會先創(chuàng)建再設(shè)置值(也就是“不存在即設(shè)置”),為了能達(dá)到和SETNX命令一樣的效果,Redis給SET命令提供了類似的選項NX,用來實現(xiàn)“不存在即設(shè)置”。如果使用了NX選項,SET命令只有在鍵值對不存在時,才會進(jìn)行設(shè)置,否則不做賦值操作。此外,SET命令在執(zhí)行時還可以帶上EX或PX選項,用來設(shè)置鍵值對的過期時間。舉個例子,執(zhí)行下面令時,只有key不存在時,SET才會創(chuàng)建key,并對key進(jìn)行賦值。另外,key的存活時間由seconds或者milliseconds選項值來決定。1SETkeyvalue[EXseconds|PXmilliseconds]有了SET命令的NX和EX/PX選項后,我們就可以用下面令來實現(xiàn)加鎖操作了//加鎖,unique_valueSETlock_keyunique_valueNXPX其中,unique_value是客戶端的唯一標(biāo)識,可以用一個隨機生成的字符串來表示,PX10000則表示lock_key會在10s//釋放鎖比較unique_valueifredis.call("get",KEYS[1])==ARGV[1]returnreturn這是使用Lua(unlock.script)實現(xiàn)的釋放鎖操作的偽代碼,其中,KEYS[1]表示lock_key,ARGV[1]是當(dāng)前客戶端的唯一標(biāo)識,這兩個值都是我們在執(zhí)行Lua時作為1redis-cli--evalunlock.scriptlock_key,你可能也注意到了,在釋放鎖操作中,我們使用了Lua,這是因為,釋放鎖操作的邏輯也包含了鎖變量、判斷值、刪除鎖變量的多個操作,而Redis在執(zhí)行Lua時,好了,到這里,你了解了如何使用SET命令和Lua在Redis單節(jié)點上實現(xiàn)分布式鎖。但是,我們現(xiàn)在只用了一個Redis實例來保存鎖變量,如果這個Redis實例發(fā)生故障宕機了,那么鎖變量就沒有了。此時,客戶端也無法進(jìn)行鎖操作了,這就會影響到業(yè)務(wù)的正常執(zhí)行。所以,我們在實現(xiàn)分布式鎖時,還需要保證鎖的可靠性。那怎么提高呢?這就要提到基于多個Reis節(jié)點實現(xiàn)分布式鎖的方式了。當(dāng)我們要實現(xiàn)高可靠的分布式鎖時,就不能只依賴單個令操作了,我們需要按照一定的步驟和規(guī)則進(jìn)行加操作,否則,就可能會出現(xiàn)鎖無法工作的情況?!耙欢ǖ牟襟E和為了避免Redis實例故障而導(dǎo)致的鎖無法工作的問題,Redis的開發(fā)者Antirez提出了分布式鎖算法Redlock。Relock算法的基本思路,是讓客戶端和多個獨立的Reis實例依次請求加鎖,如果客戶端能夠和半數(shù)以上的實例成功地完成加鎖操作,那么我們就認(rèn)為,客戶端成功地獲得分布式鎖了,否則加鎖失敗。這樣一來,即使有單個Reis實例發(fā)生故障,因為鎖變量在其它實例上也有保存,所以,客戶端仍然可以正常地進(jìn)行鎖操作,鎖變量并不會丟失。我們來具體看下Redlock算法的執(zhí)行步驟。Redlock算法的實現(xiàn)需要有N個獨立的N個Redis這里的加鎖操作和在單實例上執(zhí)行的加鎖操作一樣,使用SET命令,帶上NX,EX/PX選項,以及帶上客戶端的唯一標(biāo)識。當(dāng)然,如果某個Redis實例發(fā)生故障了,為了保證在這種情況下,Redlock算法能夠繼續(xù)運行,我們需要給加鎖操作設(shè)置一個超時時間。Redis會和下一個Redis實例繼續(xù)請求加鎖。加鎖操作的超時時間需要遠(yuǎn)遠(yuǎn)地小于鎖的有效時Redis條件一:客戶端從超過半數(shù)(N/2+1)Redis在滿足了這兩個條件后,我們需要重新計算這把鎖的有效時間,計算的結(jié)果是鎖的最初有效時間減去客戶端為獲取鎖的總耗時。如果鎖的有效時間已經(jīng)來不及完成共享數(shù)據(jù)的操作了,我們可以釋放鎖,以免出現(xiàn)還沒完成數(shù)據(jù)操作,鎖就過期了的情況。當(dāng)然,如果客戶端在和所有實例執(zhí)行完加鎖操作后,沒能同時滿足這兩個條件,那么,客戶端向所有Reis節(jié)點發(fā)起釋放鎖的操作。在Redlock算法中,釋放鎖的操作和在單實例上釋放鎖的操作一樣,只要執(zhí)行釋放鎖的Lua就可以了。這樣一來,只要N個Redis實例中的半數(shù)以上實例能正常工作,就能Redlock鎖或釋放鎖操作。Redis作為一個共享系統(tǒng),可以用來實現(xiàn)分布式鎖。在基于單個Redis方式完成,所以,我們使用SET命令帶上NX選項來實現(xiàn)加鎖;以,我們在SET命令執(zhí)行時加上EX/PX選項,設(shè)置其過期時間;SETRedis原子性地執(zhí)行Lua,來保證釋放鎖操作的原子性不過,基于單個Redis實例實現(xiàn)分布式鎖時,會實例異常或的情況,這會導(dǎo)致實例無法提供鎖操作,正因為此,Reis也提供了Relock算法,用來實現(xiàn)基于多個實例的分布式鎖。這樣一來,鎖變量由多個實例,即使有實例發(fā)生了故障,鎖變量仍然是存在的,客戶端還是可以完成鎖操作。Relock算法是實現(xiàn)高可靠分布式鎖的一種有效解決方案,你可以在實際應(yīng)用中把它用起來。按照慣例,我給你提個小問題。這節(jié)課,我提到,我們可以使用SET命令帶上NX和EX/PX選項進(jìn)行加鎖操作,那么,請你再思考一下,我們是否可以用下面的方式來實//SETNXl

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論