1. 程式人生 > >聊聊zookeeper的分散式鎖

聊聊zookeeper的分散式鎖

  分散式鎖就是多臺機器,分佈在不同的JVM中,這些不同JVM內的方法需要獲取一個唯一鎖,比如獲取鎖之後要把資料寫入資料庫,保證資料在同一時刻只有一臺機器寫入資料庫。

  分散式鎖的實現有多種實現方法,除了今天聊到的ZK實現的分散式鎖還有Redis通過SETNXPX或Lua指令碼實現,還可以通過資料庫的鎖實現,但今天咱們主要聊一下ZK的分散式鎖的原理實現。

  zookeeper可以建立兩種節點,一種是永久型的,一種是臨時型還可以是有序的,當機器與zk失去連線的時候臨時節點會自動刪除,這個功能非常強大以至於很多功能都是基於此,比如leader選舉等。現在直接上一張我自己畫的圖:

  

  首先會有一個永久節點\Locks,然後每個客戶端請求的時候會建立一個臨時有序節點,在這時每個都是有序的,最小的節點就意味著獲取了鎖。

       在此圖上顯然ClientC獲取了鎖,其他的鎖獲取的節點不是最小的,但是他們之前會有一個連結,就是lock_00000001在雖然沒有獲取鎖,但是會需要監聽lock_00000000的,因為如果監聽所有節點的話會浪費很多的資源。相應的大的節點都會watch比自己小的節點,當比自己節點小的節點釋放之後然後就可以繼續處理了。

  我們看看Curator很好的幫我們實現了這樣的功能,所有大家可以直接拿過來用:  

        InterProcessMutex lock = new InterProcessMutex(client, lockPath);
        try {
            lock.acquire(seconds
, TimeUnit.SECONDS); //do something } catch (Exception e) { logger.error("error", e); } finally { lock.release(); }

  很多東西都為我們封裝好了,如果用原生zookeepr API需要寫太多的行,並且需要考慮的點非常的多。我在網上也找了一個例子,自己改了一把,然後跑了沒有什麼問題, 因為不是自己寫的,所有不貼出來了,有需要了自行下載: https://github.com/stonehqs/Demo/blob/master/ZookeeperLock.java

  但是在這裡邊我能想到的還有一場景需要大家一起思考一下:

  1. 如果ZK叢集出問題了,如何處理?

  2. 如果方法呼叫的太頻繁,這樣會出現連線ZK被拒絕,比如一個應用連線數超過60個。

  大家如果有更好的方案,可以給我留言討論。

  我能想到的第1點就是採用多個叢集,比如兩個叢集,在寫入資料的時候同時寫入到兩個叢集中(保證資料一致),如果有一個群集中超過一半不能使用的時候,那麼整個叢集不能用了,這時可以切換到另一個群集,保證訪問的高可用。 

  關於第2點,每個連線ZK群集的IP會被記錄下來,這樣一個IP連線ZK叢集的最大預設數量60個,如果超過60個的話會被拒絕連線,防止DDOS攻擊。所以在每個應用的方法呼叫的時候需要加入synchronized關鍵字,這樣每個應用在同一時刻有一個執行緒在進行處理,其他的執行緒可以等待或者直接去做別的處理。還有另一個方案就是調整這個數變大,這樣也可以解決一下,但是如果調整的話還需要多做一些測試,保證這個數字是最佳的。

  好了,有問題的可以給我留言。下期再見。