zookeeper模擬伺服器端啟動註冊,客戶端感知伺服器上下線
阿新 • • 發佈:2019-01-24
1.首先編寫伺服器端程式,原理就是上線一臺伺服器就會在/server這個組目錄下建立一個節點server,節點的值為臨時的(session消失後值也會消失)且為序列的(自動分配序列號),這樣伺服器上線下線,zookeeper的znode中的資料也會同步上建立和刪除。
伺服器端模擬程式碼如下:
package com.lijie.zk2;
import java.security.acl.Acl;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
public class MyServer {
private static final String connectString = "hadoop01:2181,hadoop02:2181,hadoop03:2181";
private static final int sessionTimeout = 2000;
private static ZooKeeper zk = null ;
private static String group = "/server";
public static void main(String[] args) throws Exception {
//註冊
regServer("192.168.80.123");
//執行任務
business("192.168.80.123");
}
/**
* 獲取zookeeper例項
* @return
* @throws Exception
*/
public static ZooKeeper getZookeeper() throws Exception {
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent event) {
// 收到watch通知後的回撥函式
System.out.println("事件型別" + event.getType() + ",路徑" + event.getPath());
//因為監聽器只會監聽一次,這樣可以一直監聽,且只監聽"/"目錄
try {
zk.getChildren("/", true);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
return zk;
}
/**
* 註冊到zookeeper
* @param ip
* @throws Exception
*/
public static void regServer(String ip) throws Exception {
zk = getZookeeper();
String create = zk.create(group + "/server", ip.getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(ip + " 上線了!" + ",儲存路徑:" + create);
}
/**
* 業務
* @throws Exception
*/
public static void business(String ip) throws Exception {
System.out.println(ip + " 處理業務");
Thread.sleep(Long.MAX_VALUE);
}
}
2.然後編寫客戶端程式,原理就是執行對/server下面子節點的檢視並且監聽,其實就相當於ls /server watch,並且在process方法中再次呼叫getList方法更新列表並監聽,如果/server子節點有新增或者刪除,那麼這個監聽就會被觸發。
package com.lijie.zk2;
import java.util.ArrayList;
import java.util.List;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
public class MyClient {
private static final String connectString = "hadoop01:2181,hadoop02:2181,hadoop03:2181";
private static final int sessionTimeout = 2000;
private static ZooKeeper zk = null;
private static String group = "/server";
private static volatile List<String> ipList = null;
public static void main(String[] args) throws Exception {
//獲取列表並且監聽
getList();
//執行業務
business();
}
/**
* 獲取zookeeper例項
* @return
* @throws Exception
*/
public static ZooKeeper getZookeeper() throws Exception {
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent event) {
// 收到watch通知後的回撥函式
System.out.println("事件型別" + event.getType() + ",路徑" + event.getPath());
//重新更新列表,並註冊監聽
try {
getList();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
return zk;
}
/**
* 獲取伺服器列表,並監聽父節點下面的變化
* @return
* @throws Exception
*/
public static void getList() throws Exception {
zk = getZookeeper();
//獲取節點名字
List<String> children = zk.getChildren(group, true);
//宣告裝載服務ip的集合
ArrayList<String> ips = new ArrayList<String>();
for (String path : children) {
//獲取資料
byte[] data = zk.getData(group + "/" + path, false, null);
ips.add(new String(data));
}
ipList = ips;
//列印伺服器列表
System.out.println("列印伺服器列表" + ipList);
}
/**
* 業務
* @throws Exception
*/
public static void business() throws Exception {
System.out.println("客戶端處理");
Thread.sleep(Long.MAX_VALUE);
}
}
啟動兩個伺服器端,結果如圖
第一個:
第二個:
啟動客戶端:
注意:上面的伺服器端執行沒有問題,但是客戶端執行的時候其實給我報錯了,但是當我debug的時候卻又沒問題(org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /server/server0000000002
),如下:
網上查詢資料說是因為要先等zookeeper連線之後再執行後面的,可以使用CountDownLatch去控制,但是我這裡報這個錯之前會有這些ip顯示出來,應該不是這個問題,而且使用CountDownLatch去控制了依舊沒有效果,這個錯誤先放這,下次來解決。