分布式之Zookeeper一(分布式鎖與Zookeeper集群)


  說到分布式開發,不得不說的就是zookeeper了;zookeeper官網說到Apache ZooKeeper致力於開發和維護可實現高度可靠的分布式協調的開源服務器那么zk作為一個協調者的存在,是分布式比不可少的一部分。廢話不多說,直接上干貨

  Zookeeper(https://zookeeper.apache.org/)的安裝包可以直接在官網上獲取,https://zookeeper.apache.org/doc/current/zookeeperStarted.html這里有Zookeeper的一些常用的簡單命令,我們可以嘗試着去試試它。

  下面來說分布式鎖,它用到的場景;比如:我們常說的驚群效應、Zookeeper集群爭先讀取緩存等。這里可能有人提到用redis實現的分布式鎖,其實對比redis和Zookeeper的官網敘述,我們就能清晰的發現:Zookeeper比Redis更適合去做分布式鎖。Zookeeper的擔保第一條就是它的順序性和一致性,其次是它的原子性。大家也可以詳細的去了解一下。再分清楚這些之后,我們可以試着思考下Zookeeper它是怎么去實現的分布式鎖?根據什么去實現的?

  可以想到如何獲取到Zookeeper的每個節點以及子節點變化,Zookeeper的Watch機制充分的實現了這一點。通過Watch機制可以清晰的監聽到Zookeeper的每個節點的變化。自然而然的這里也要用到Zookeeper的第三方客戶端。Zookeeper的第三方客戶端有兩個;一個是zkclient、一個是curator。在curator中它自己已經實現了分布式鎖,感興趣的可以去看看它的實現源碼。

  在第三方客戶端連接到Zookeeper之后,就可以開始實現分布式鎖了。鎖的排他性、堵塞性、可重入性。排他性zk默認就實現了,zk的節點必須是唯一的。分布式鎖采用Zookeeper的臨時順序節點來實現,首先獲取鎖,創建一個Zookeeper的臨時順序節點;然后需要一個柵欄(CountDownLatch),確保所有人都拿到自己的編號,即在同一起跑線上。然后開始搶鎖,給一個發令槍(CountDown)。然后搶到鎖的就去執行自己的業務,watch再次監聽節點數據變化,然后請求線程去進行阻塞等待,接下來再刪除節點,釋放鎖。

 

 1 public boolean tryLock() {
 2         
 3         if(currentPath.get() == null || !client.exists(currentPath.get())) {
 4             String node = client.createEphemeralSequential(LockPath+"/", "locked");
 5             currentPath.set(node);
 6         }
 7         
 8         
 9         List<String> children =client.getChildren(LockPath);
10         // 排序list
11         Collections.sort(children);
12         
13         // 判斷當前節點是否是最小的
14         if(currentPath.get().equals(LockPath+"/"+children.get(0))) {
15             return true;
16         }else {
17             
18             int curIndex = children.indexOf(currentPath.get().substring(LockPath.length() + 1));
19             String bnode = LockPath+"/"+children.get(curIndex -1);
20             beforePath.set(bnode);
21         }
22         return false;
23     }
24 
25 
26     public void lock() {
27         if(! tryLock()) {
28             // 阻塞等待鎖的釋放
29             waitForLock();
30             // 重新搶鎖
31             lock();
32         }
33     }
34     private void waitForLock() {
35         
36         CountDownLatch cdl = new CountDownLatch(1);
37         // 用zkwatcher事件來通知
38             IZkDataListener listener = new IZkDataListener() {
39 
40             public void handleDataDeleted(String dataPath) throws Exception {
41                 System.out.println("================zk節點被刪除================");
42                 cdl.countDown();
43             }
44 
45             public void handleDataChange(String dataPath, Object data) throws Exception {
46             }
47         };
48         // watcher /zk 數據變化
49         client.subscribeDataChanges(beforePath.get(), listener);
50         
51         // 請求線程去進行阻塞等待
52         if(client.exists(beforePath.get())) {
53             try {
54                 cdl.await();
55             } catch (InterruptedException e) {
56                 e.printStackTrace();
57             }
58         }
59         // 取消注冊事件
60         client.unsubscribeDataChanges(beforePath.get(), listener);
61     }

至此一個分布式鎖就實現了。

  接下來說Zookeeper的偽集群。搭建的時候需要注意的情況:
1、DataDir的位置。
2、Zookeeper的端口號
3、


4、myid文件,myid文件是創建在DataDir目錄下的,myid文件就是給一個id數,id數需與server.1 ... 后邊的編號一致。
然后分別啟動三台服務器,注意看服務器輸出的日志消息。不出意外的話Zookeeper的集群就可以搭建成功了!

 

 

 
        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM