jedis實現分布式鎖

2021-10-03 14:48:48 字數 1838 閱讀 1645

1.互斥性。在任意時刻,只有乙個客戶端能持有鎖。

2.不會發生死鎖。即使有乙個客戶端在持有鎖的期間崩潰而沒有主動解鎖,也能保證後續其他客戶端能加鎖。

3.具有容錯性。只要大部分的redis節點正常執行,客戶端就可以加鎖和解鎖。

4.解鈴還須繫鈴人。加鎖和解鎖必須是同乙個客戶端,客戶端自己不能把別人加的鎖給解了。

//加鎖

public

class

redistool

return

false;}

}

可以看到,我們加鎖就一行**:jedis.set(string key, string value, string n***, string expx, int time),這個set()方法一共有五個形參:

1.第乙個為key,我們使用key來當鎖,因為key是唯一的。

2.第二個為value,我們傳的是requestid,很多童鞋可能不明白,有key作為鎖不就夠了嗎,為什麼還要用到value?原因就是我們在上面講到可靠性時,分布式鎖要滿足第四個條件解鈴還須繫鈴人,通過給value賦值為requestid,我們就知道這把鎖是哪個請求加的了,在解鎖的時候就可以有依據。requestid可以使用uuid.randomuuid().tostring()方法生成。

3.第三個為n***,這個引數我們填的是nx,意思是set if not exist,即當key不存在時,我們進行set操作;若key已經存在,則不做任何操作;

4.第四個為expx,這個引數我們傳的是px,意思是我們要給這個key加乙個過期的設定,具體時間由第五個引數決定。

5.第五個為time,與第四個引數相呼應,代表key的過期時間。

總的來說,執行上面的set()方法就只會導致兩種結果:1. 當前沒有鎖(key不存在),那麼就進行加鎖操作,並對鎖設定個有效期,同時value表示加鎖的客戶端。2. 已有鎖存在,不做任何操作。

心細的童鞋就會發現了,我們的加鎖**滿足我們可靠性裡描述的三個條件。首先,set()加入了nx引數,可以保證如果已有key存在,則函式不會呼叫成功,也就是只有乙個客戶端能持有鎖,滿足互斥性。其次,由於我們對鎖設定了過期時間,即使鎖的持有者後續發生崩潰而沒有解鎖,鎖也會因為到了過期時間而自動解鎖(即key被刪除),不會發生死鎖。最後,因為我們將value賦值為requestid,代表加鎖的客戶端請求標識,那麼在客戶端在解鎖的時候就可以進行校驗是否是同乙個客戶端。由於我們只考慮redis單機部署的場景,所以容錯性我們暫不考慮。

//釋放鎖

public

class

redistool

return

false;}

}

可以看到,我們解鎖只需要兩行**就搞定了!第一行**,我們寫了乙個簡單的lua指令碼**,上一次見到這個程式語言還是在《黑客與畫家》裡,沒想到這次居然用上了。第二行**,我們將lua**傳到jedis.eval()方法裡,並使引數keys[1]賦值為lockkey,ar**[1]賦值為requestid。eval()方法是將lua**交給redis服務端執行。

那麼這段lua**的功能是什麼呢?其實很簡單,首先獲取鎖對應的value值,檢查是否與requestid相等,如果相等則刪除鎖(解鎖)。那麼為什麼要使用lua語言來實現呢?因為要確保上述操作是原子性的。關於非原子性會帶來什麼問題,可以閱讀【解鎖**-錯誤示例2】 。那麼為什麼執行eval()方法可以確保原子性,源於redis的特性,下面是官網對eval命令的部分解釋:

簡單來說,就是在eval命令執行lua**的時候,lua**將被當成乙個命令去執行,並且直到eval命令執行完成,redis才會執行其他命令。

如果你的專案中redis是多機部署的,那麼可以嘗試使用redisson實現分布式鎖

分布式鎖 使用Redis實現分布式鎖

關於分布式鎖的實現,我的前一篇文章講解了如何使用zookeeper實現分布式鎖。關於分布式鎖的背景此處不再做贅述,我們直接討論下如何使用redis實現分布式鎖。關於redis,筆主不打算做長篇大論的介紹,只介紹下redis優秀的特性。支援豐富的資料型別,如string list map set zs...

分布式鎖實現

1,資料庫實現原理 資料庫的行級x鎖。優點 不需要引入第三方應用。缺點 死鎖 對資料庫效能影響,可能較長時間占用資料庫連線資源 如果業務是分庫分表的,可能支援不了 示例 2,快取實現原理 通過setnx是否成功。當且僅當 key 不存在,將 key 的值設為 value 並返回1 若給定的 key ...

Jedis分布式鎖實際應用筆記

前幾日做了乙個類似論壇的功能實現,話不多說,上 工具類 jedisutil component public class jedisutil public void setjedisclusterprefix string jedisclusterprefix value private void ...