分佈式鎖的兩種實現方式(基於redis和基於zookeeper)

先來講說什麼是分佈式鎖,簡單來講,分佈式鎖就是在分佈式併發場景中,可以實現多節點的代碼同步的一種機制。從實現角度來看,主要有兩種方式:基於redis的方式和基於zookeeper的方式,下面分別簡單介紹下這兩種方式:html

請尊重做者勞動成果,轉載請標明原文連接:node

http://www.javashuo.com/article/p-rjgwjyjv-db.htmlweb

1、基於redis的分佈式鎖實現redis

1.獲取鎖 數據庫

redis是一種key-value形式的NOSQL數據庫,經常使用於做服務器的緩存。從redis v2.6.12開始,set命令開始變成以下格式:緩存

SET key value [EX seconds] [PX milliseconds] [NX|XX]

除key和value外,EX是超時時間,NX表示只有在key不存在的時候纔會設置key的值,而XX表示在key存在的時間纔會設置key的值。NX機制就是基於redis分佈式鎖的核心。可以解決如下問題:服務器

1)節點1獲取key,而且設置超時時間後,還沒來得及釋放就掛掉了——這裏EX超時時間會發揮做用,超時後自動釋放鎖。併發

2)剛獲取到鎖,還沒來得及設置超時時間就掛了——這裏設置key和設置超時時間是原子操做,若是出現這種狀況,會返回0,即獲取不到鎖。分佈式

2.釋放鎖lua

爲了解決非原子操做帶來的問題,常採用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)); 

2、基於zookeeper的分佈式鎖實現 

zookeeper是一種分佈式協調服務,其中每一個節點稱爲znode,並有本身獨立的路徑。 znode有四種類型:

  持久節點:默認的節點類型。建立節點的客戶端與zookeeper斷開鏈接後,該節點依舊存在 。
  持久節點順序節點:所謂順序節點,就是在建立節點時,Zookeeper根據建立的時間順序給該節點名稱進行編號:
  臨時節點:和持久節點相反,當建立節點的客戶端與zookeeper斷開鏈接後,臨時節點會被刪除:
  臨時順序節點:結合和臨時節點和順序節點的特色:在建立節點時,Zookeeper根據建立的時間順序給該節點名稱進行編號;當建立節點的客戶端與zookeeper斷開鏈接後,臨時節點會被刪除。

下面看看是怎樣基於上面的四類節點實現分佈式鎖的。

1.獲取鎖

1)在Zookeeper當中建立一個持久節,當第一個客戶端Client1想要得到鎖時,須要在這個節點下面建立一個臨時順序節點。
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就崩潰了,也會自動釋放鎖。 

相關文章
相關標籤/搜索