用redis構建分布式鎖

2022-09-16 01:45:13 字數 1676 閱讀 1086

從2.6.12版本開始,redis為set命令增加了一系列選項:

如果有2個程序(可能位於不同機器)需要競爭某個資源,可以為這個資源加鎖,鎖放在redis裡面,這樣兩個程序都能訪問到,例如下面的命令:

set resource-name random-value nx ex max-lock-time

僅當key不存在時,設定乙個鍵值對,並且設定了key的過期時間。

如果其中乙個程序set成功,那麼另外乙個程序會set失敗,只要判斷set命令的返回值,就可以判斷是否加鎖成功。

這裡resouce-name是需要加鎖的資源,而random-value每個程序都可以寫唯一值,而max-lock-time是鎖的最大持有時間。

如何釋放鎖:

a客戶端獲得的鎖(鍵key)已經由於過期時間到了被redis伺服器刪除,但是這個時候a客戶端還去執行del命令。而b客戶端已經在a設定的過期時間之後重新獲取了這個同樣key的鎖,那麼a執行del就會釋放了b客戶端加好的鎖。

if redis.call("

get",keys[1]) == ar**[1

]then

return redis.call("

del",keys[1

])else

return

0end

由於每個程序寫入的value是自己生成的隨機數,可以保證乙個程序只能刪除自己加的鎖,而避免誤刪其它程序加的鎖。

在分布式版本的演算法裡我們假設我們有n個redis master節點,這些節點都是完全獨立的,我們不用任何複製或者其他隱含的分布式協調演算法。我們已經描述了如何在單節點環境下安全地獲取和釋放鎖。因此我們理所當然地應當用這個方法在每個單節點裡來獲取和釋放鎖。在我們的例子裡面我們把n設成5,這個數字是乙個相對比較合理的數值,因此我們需要在不同的計算機或者虛擬機器上執行5個master節點來保證他們大多數情況下都不會同時宕機。乙個客戶端需要做如下操作來獲取鎖:

1.獲取當前時間(單位是毫秒)。

2.輪流用相同的key和隨機值在n個節點上請求鎖,在這一步裡,客戶端在每個master上請求鎖時,會有乙個和總的鎖釋放時間相比小的多的超時時間。比如如果鎖自動釋放時間是10s,那每個節點鎖請求的超時時間可能是5~50ms的範圍,這個可以防止乙個客戶端在某個宕掉的master節點上阻塞過長時間,如果乙個master節點不可用了,我們應該盡快嘗試下乙個master節點。

3.客戶端計算第二步中獲取鎖所花的時間,只有當客戶端在大多數master節點上成功獲取了鎖(在這裡是3個),而且總共消耗的時間不超過鎖釋放時間,這個鎖就認為是獲取成功了。

4.如果鎖獲取成功了,那現在鎖自動釋放時間就是最初的鎖釋放時間減去之前獲取鎖所消耗的時間。

5.如果鎖獲取失敗了,不管是因為獲取成功的鎖不超過一半(n/2+1)還是因為總消耗時間超過了鎖釋放時間,一定要盡快在獲取鎖成功的節點上釋放鎖,這樣就沒必要等到key超時後才能重新獲取這個鎖(但是如果網路分割槽的情況發生而且客戶端無法連線到redis節點時,會損失等待key超時這段時間的系統可用性)。

注意:當乙個客戶端獲取鎖失敗時,這個客戶端應該在乙個隨機延時後進行重試,之所以採用隨機延時是為了避免不同客戶端同時重試導致誰都無法拿到鎖的情況出現。同樣的道理客戶端越快嘗試在大多數redis節點獲取鎖,出現多個客戶端同時競爭鎖和重試的時間視窗越小,可能性就越低,所以最完美的情況下,客戶端應該用多路傳輸的方式同時向所有redis節點傳送set命令。

用redis實現分布式鎖

通常部署的服務都是在多台伺服器上,不會只有一台。那麼在分布式環境下,就會遇到共享資源的問題。比如乙個人只能有一條記錄,下次進來就只能修改,而不是再新增。如果只有一台伺服器,可以使用多執行緒下的單例模式來控制,但是分布式下,就不管用了。有三種方式,一是使用資料庫的樂觀鎖,二是redis的鎖,三是zoo...

使用redis構建可靠分布式鎖

關於分布式鎖的概念,具體實現方式,直接參閱下面兩個帖子,這裡就不多介紹了。分布式鎖的多種實現方式 分布式鎖總結 對於分布式鎖的幾種實現方式的優劣,這裡再列舉下 1.資料庫實現方式 優點 易理解 缺點 運算元據庫消耗較大,效能較低。為了處理一些異常,會使得整個方案越來越複雜 2.快取實現方式 優點 效...

redis分布式鎖

redis分布式鎖 直接上 我寫了四個redis分布式鎖的方法,大家可以提個意見 第一種方法 redis分布式鎖 param timeout public void lock long timeout thread.sleep 100 catch exception e override publi...