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

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

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

溫馨提示

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

評論

0/150

提交評論