基於zookeeper實現的分佈式鎖

用zk原生api實現的鎖,大體思想:html

每一個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個惟一的瞬時有序臨時節點。 判斷是否獲取鎖的方式很簡單,只須要判斷有序節點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節點刪除便可。能夠避免服務宕機致使的鎖沒法釋放,而產生的死鎖問題。java

示例:http://www.cnblogs.com/liuyang0/p/6800538.html

來看下Zookeeper可能存在一些問題:git

  • 鎖沒法釋放?使用Zookeeper能夠有效的解決鎖沒法釋放的問題,由於在建立鎖的時候,客戶端會在ZK中建立一個臨時節點,一旦客戶端獲取到鎖以後忽然掛掉(Session鏈接斷開),那麼這個臨時節點就會自動刪除掉。其餘客戶端就能夠再次得到鎖。github

  • 非阻塞鎖?使用Zookeeper能夠實現阻塞的鎖,客戶端能夠經過在ZK中建立順序節點,而且在節點上綁定監聽器,一旦節點有變化,Zookeeper會通知客戶端,客戶端能夠檢查本身建立的節點是否是當前全部節點中序號最小的,若是是,那麼本身就獲取到鎖,即可以執行業務邏輯了。數據庫

  • 不可重入?使用Zookeeper也能夠有效的解決不可重入的問題,客戶端在建立節點的時候,把當前客戶端的主機信息和線程信息直接寫入到節點中,下次想要獲取鎖的時候和當前最小的節點中的數據比對一下就能夠了。若是和本身的信息同樣,那麼本身直接獲取到鎖,若是不同就再建立一個臨時的順序節點,參與排隊。apache

  • 單點問題?使用Zookeeper能夠有效的解決單點問題,ZK是集羣部署的,只要集羣中有半數以上的機器存活,就能夠對外提供服務。api

缺點

  • 性能上不如使用緩存實現分佈式鎖。由於每次在建立鎖和釋放鎖的過程當中,都要動態建立、銷燬瞬時節點來實現鎖功能。ZK中建立和刪除節點只能經過Leader服務器來執行,而後將數據同步到全部的Follower機器上。緩存

  • 另外Zookeeper也有可能存在併發問題,只是不常見而已。因爲網絡抖動,客戶端與ZK集羣的session鏈接斷了,那麼zk覺得客戶端掛了,就會刪除臨時節點,這時候其餘客戶端就能夠獲取到分佈式鎖了,從而致使併發問題。解決方案,zk有重試機制,一旦zk集羣檢測不到客戶端的心跳,就會重試,Curator客戶端支持多種重試策略。屢次重試以後還不行的話纔會刪除臨時節點。(因此,選擇一個合適的重試策略也比較重要,要在鎖的粒度和併發之間找一個平衡。)服務器

優勢

有效的解決單點問題,不可重入問題,非阻塞問題以及鎖沒法釋放的問題。實現起來較爲簡單。網絡

三者比較

  • 從理解的難易程度角度(從低到高)

數據庫 > 緩存 > Zookeeper

  • 從實現的複雜性角度(從低到高)

Zookeeper >= 緩存 > 數據庫

  • 從性能角度(從高到低)

緩存 > Zookeeper >= 數據庫

  • 從可靠性角度(從高到低)

Zookeeper > 緩存 > 數據庫

能夠直接使用zookeeper第三方庫Curator方便地實現分佈式鎖,代碼示例

https://github.com/xuyang0902/zklock/blob/master/src/main/java/com/tongbanjie/zk/lock/core/ZkDistributedLock.java

Curator提供的InterProcessMutex是分佈式鎖的實現。

//獲取鎖(阻塞,直到搶到鎖)
public void acquire() 
Acquire the mutex - blocking until it's available. Note: the same thread can call acquire re-entrantly. Each call to acquire must be balanced by a call to release() 

//提供帶入參方法,支持超時釋放
public boolean acquire(long time,TimeUnit unit) 
Acquire the mutex - blocks until it's available or the given time expires. Note: the same thread can call acquire re-entrantly. Each call to acquire that returns true must be balanced by a call to release() 
Parameters: 
time - time to wait 
unit - time unit 
Returns: 
true if the mutex was acquired, false if not

// 釋放鎖
public void release()

官方提供的示例:

https://github.com/apache/curator/blob/master/curator-examples/src/main/java/locking/ExampleClientThatLocks.java

相關文章
相關標籤/搜索