您好,登錄后才能下訂單哦!
說到分布式開發,不得不說的就是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再次監聽節點數據變化,然后請求線程去進行阻塞等待,接下來再刪除節點,釋放鎖。
public boolean tryLock() {
if(currentPath.get() == null || !client.exists(currentPath.get())) {
String node = client.createEphemeralSequential(LockPath+"/", "locked");
currentPath.set(node);
}
List<String> children =client.getChildren(LockPath);
// 排序list
Collections.sort(children);
// 判斷當前節點是否是最小的
if(currentPath.get().equals(LockPath+"/"+children.get(0))) {
return true;
}else {
int curIndex = children.indexOf(currentPath.get().substring(LockPath.length() + 1));
String bnode = LockPath+"/"+children.get(curIndex -1);
beforePath.set(bnode);
}
return false;
}
public void lock() {
if(! tryLock()) {
// 阻塞等待鎖的釋放
waitForLock();
// 重新搶鎖
lock();
}
}
private void waitForLock() {
CountDownLatch cdl = new CountDownLatch(1);
// 用zkwatcher事件來通知
IZkDataListener listener = new IZkDataListener() {
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("================zk節點被刪除================");
cdl.countDown();
}
public void handleDataChange(String dataPath, Object data) throws Exception {
}
};
// watcher /zk 數據變化
client.subscribeDataChanges(beforePath.get(), listener);
// 請求線程去進行阻塞等待
if(client.exists(beforePath.get())) {
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 取消注冊事件
client.unsubscribeDataChanges(beforePath.get(), listener);
}
至此一個分布式鎖就實現了。
接下來說Zookeeper的偽集群。搭建的時候需要注意的情況:
1、DataDir的位置。
2、Zookeeper的端口號
3、myid文件,myid文件是創建在DataDir目錄下的,myid文件就是給一個id數,id數需與server.1 ... 后邊的編號一致。
然后分別啟動三臺服務器,注意看服務器輸出的日志消息。不出意外的話Zookeeper的集群就可以搭建成功了!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。