先來說說什么是分布式鎖,簡單來說,分布式鎖就是在分布式並發場景中,能夠實現多節點的代碼同步的一種機制。從實現角度來看,主要有兩種方式:基於redis的方式和基於zookeeper的方式,下面分別簡單介紹下這兩種方式:
請尊重作者勞動成果,轉載請標明原文鏈接:
https://www.cnblogs.com/jpcflyer/p/9142813.html
一、基於redis的分布式鎖實現
1.獲取鎖
redis是一種key-value形式的NOSQL數據庫,常用於作服務器的緩存。從redis v2.6.12開始,set命令開始變成如下格式:
除key和value外,EX是超時時間,NX表示只有在key不存在的時候才會設置key的值,而XX表示在key存在的時間才會設置key的值。NX機制就是基於redis分布式鎖的核心。能夠解決以下問題:
1)節點1獲取key,並且設置超時時間后,還沒來得及釋放就掛掉了——這里EX超時時間會發揮作用,超時后自動釋放鎖。
2)剛獲取到鎖,還沒來得及設置超時時間就掛了——這里設置key和設置超時時間是原子操作,如果出現這種情況,會返回0,即獲取不到鎖。
2.釋放鎖
為了解決非原子操作帶來的問題,常采用lua腳本實現。lua腳本的操作會被認為是原子性的,類似於事務。偽代碼如下:
String luaScript =
"if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
redisClient.eval(luaScript , Collections.singletonList(key), Collections.singletonList(threadId));
二、基於zookeeper的分布式鎖實現
zookeeper是一種分布式協調服務,其中每個節點稱為znode,並有自己獨立的路徑。 znode有四種類型:
持久節點順序節點:所謂順序節點,就是在創建節點時,Zookeeper根據創建的時間順序給該節點名稱進行編號:
臨時節點:和持久節點相反,當創建節點的客戶端與zookeeper斷開連接后,臨時節點會被刪除:
臨時順序節點:結合和臨時節點和順序節點的特點:在創建節點時,Zookeeper根據創建的時間順序給該節點名稱進行編號;當創建節點的客戶端與zookeeper斷開連接后,臨時節點會被刪除。
下面看看是怎樣基於上面的四類節點實現分布式鎖的。
1.獲取鎖
2)Client1查找持久節點下面所有的臨時順序節點並排序,判斷自己所創建的節點是不是順序最靠前的一個。如果是第一個節點,則成功獲得鎖。
3)如果再有一個客戶端 Client2 前來獲取鎖,則在持久節點下面再創建一個臨時順序節點Lock2。
4)Client2查找持久節點下面所有的臨時順序節點並排序,判斷自己所創建的節點Lock2是不是順序最靠前的一個,結果發現節點Lock2並不是最小的。
於是,Client2向排序僅比它靠前的節點Lock1注冊Watcher,用於監聽Lock1節點是否存在。這意味着Client2搶鎖失敗,進入了等待狀態。
5)如果又有一個客戶端Client3前來獲取鎖,則在持久節點下載再創建一個臨時順序節點Lock3。
Client3查找持久節點下面所有的臨時順序節點並排序,判斷自己所創建的節點Lock3是不是順序最靠前的一個,結果同樣發現節點Lock3並不是最小的。
於是,Client3向排序僅比它靠前的節點Lock2注冊Watcher,用於監聽Lock2節點是否存在。這意味着Client3同樣搶鎖失敗,進入了等待狀態。
2.釋放鎖
釋放鎖就比較簡單了,因為前面創建的臨時順序節點,所以在出現下面兩種情況時,都會自動釋放鎖:
1)任務完成后,Client會釋放鎖。
2)任務沒完成,Client就崩潰了,也會自動釋放鎖。