分布式鎖一般有三種實現方式:
資料庫樂觀鎖;
基於redis的分布式鎖;
基於zookeeper的分布式鎖
加鎖**:
public class redistool
return false;
}}
可以看到,我們加鎖就一行**:
jedis.set(string key, string value, string n***, string expx, int time)
這個set()方法一共有五個形參:
第乙個為key,我們使用key來當鎖,因為key是唯一的。
第二個為value,我們傳的是requestid,很多童鞋可能不明白,有key作為鎖不就夠了嗎,為什麼還要用到value?
原因就是我們在上面講到可靠性時,分布式鎖要滿足第四個條件解鈴還須繫鈴人,通過給value賦值為requestid,我們就知道這把鎖是哪個請求加的了,在解鎖的時候就可以有依據。
requestid可以使用uuid.randomuuid().tostring()方法生成。
第三個為n***,這個引數我們填的是nx,意思是set if not exist,即當key不存在時,我們進行set操作;若key已經存在,則不做任何操作;
第四個為expx,這個引數我們傳的是px,意思是我們要給這個key加乙個過期的設定,具體時間由第五個引數決定。
第五個為time,與第四個引數相呼應,代表key的過期時間。
總的來說,執行上面的set()方法就只會導致兩種結果:
當前沒有鎖(key不存在),那麼就進行加鎖操作,並對鎖設定個有效期,同時value表示加鎖的客戶端。
已有鎖存在,不做任何操作。
我們的加鎖**滿足我們可靠性裡描述的三個條件。
首先,set()加入了nx引數,可以保證如果已有key存在,則函式不會呼叫成功,也就是只有乙個客戶端能持有鎖,滿足互斥性。
其次,由於我們對鎖設定了過期時間,即使鎖的持有者後續發生崩潰而沒有解鎖,鎖也會因為到了過期時間而自動解鎖(即key被刪除),不會發生死鎖。
最後,因為我們將value賦值為requestid,代表加鎖的客戶端請求標識,那麼在客戶端在解鎖的時候就可以進行校驗是否是同乙個客戶端。
解鎖**:
public class redistool
return false;
}}
第一行**,我們寫了乙個簡單的lua指令碼**。
第二行**,我們將lua**傳到jedis.eval()方法裡,並使引數keys[1]賦值為lockkey,ar**[1]賦值為requestid。eval()方法是將lua**交給redis服務端執行。
那麼這段lua**的功能是什麼呢?
其實很簡單,首先獲取鎖對應的value值,檢查是否與requestid相等,如果相等則刪除鎖(解鎖)。
那麼為什麼要使用lua語言來實現呢?
因為要確保上述操作是原子性的。
那麼為什麼執行eval()方法可以確保原子性,源於redis的特性,
簡單來說,就是在eval命令執行lua**的時候,lua**將被當成乙個命令去執行,並且直到eval命令執行完成,redis才會執行其他命令。
正確方式實現Redis分布式鎖
實現分布式鎖的方式有很多 1 zookeeper 2 redis 3 阿里開源等。但是在redis中進行實現鎖的網上百分之99的案例中,都如下 long i jedis.setnx key,key if i 1 else 這個是這裡在setnx之後還沒來得及設定過期時間就宕機了,這樣會導致deadl...
基於redis分布式鎖實現方式
分布式鎖 控制分布式系統或者不同應用訪問共享資源時互斥 主要需要解決四個問題 互斥性 安全性 死鎖 容錯 setnx key value 如果key不存在,則建立並賦值 expire key seconds 給key設定過期時間 以上兩個命令搭配使用可以實現分布式鎖,但是可能會出現set成功但是未執...
分布式鎖 使用Redis實現分布式鎖
關於分布式鎖的實現,我的前一篇文章講解了如何使用zookeeper實現分布式鎖。關於分布式鎖的背景此處不再做贅述,我們直接討論下如何使用redis實現分布式鎖。關於redis,筆主不打算做長篇大論的介紹,只介紹下redis優秀的特性。支援豐富的資料型別,如string list map set zs...