一、節點操作
4 種
持久和臨時
無序和有序
1.1持久化節點
public static void createPersistent() {
if(!zkClient.exists("/java")) {
String create = zkClient.create("/java", "java", CreateMode.PERSISTENT);
System.out.println(create);
}
if(zkClient.exists("/java/io/inputstream/fileInputstream")) {
// NoNode , 這個低估創建是自己實現的算法
zkClient.createPersistent("/java/io/inputstream/fileInputstream", true); // 這個使用最多,它可以遞歸創建節點,zookeeper 原生不支持遞歸創建
}
}
/**
* 創建一個持久的順序節點
*/
public static void createPerSeq() {
// zk 不支持創建同名的節點
// /java0000000004 /java0000000005 /java0000000006
// String create = zkClient.create("/java", "java", CreateMode.PERSISTENT_SEQUENTIAL);
String create = zkClient.createPersistentSequential("/java", "java"); // 快捷創建節點
System.out.println(create);
}
1.2創建臨時節點
若創建它的客戶端斷開連接後(和zkServer 斷開),則節點會自動刪除
/**
* 臨時節點,若創建它的客戶端斷開連接,則自動死掉
* 使用多一點
*/
public static void createEm() {
zkClient.createEphemeral("/test");
try {
System.out.println("掛起jvm,線程在此一致等待");
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
// zkClient.close();
}
// 創建一個臨時的順序節點 使用少
public static void createEmSeq() {
zkClient.createEphemeralSequential("/test1", "test");
}
1.3訂閱子節點的改變(重要)
/**
* 訂閱節點的改變(重要)
*/
public static void subScribe() {
zkClient.subscribeChildChanges("/com.sxt.AddService", new IZkChildListener() {
/**
* 若該父節點的字節有變化,則會執行該方法
*/
@Override
public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
System.out.println(parentPath+",下的字節點有變化");
System.out.println("當前最新的子節點爲"+currentChilds);
}
});
System.out.println("開始監聽");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
1.4其他的訂閱操作
public static void otherSub() {
// zkClient.subscribeStateChanges(new IZkStateListener() {
//
// @Override
// public void handleStateChanged(KeeperState state) throws Exception {
// System.out.println("當前狀態爲"+state);
// }
//
// @Override
// public void handleSessionEstablishmentError(Throwable error) throws Exception {
// System.out.println("寫數據的異常"+error); // 寫數據和時有異常會監聽到
// }
//
// @Override
// public void handleNewSession() throws Exception {
// System.out.println("新連接"); // 觸發條件是在一個客戶端裏面
// }
// });// 訂閱服務器的狀態改變(zkServer狀態的改變,服務器死機了,啓動)
zkClient.subscribeDataChanges("/java", new IZkDataListener() { // 該監聽針對的是自己(客戶端)內部數據改變
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println(dataPath);
}
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
System.out.println(dataPath+":::"+data);
}
}); // 訂閱節點數據改變的通知
System.out.println("開始監聽");
try {
System.in.read();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
1.5修改節點的數據
/**
* 給節點寫數據
*/
public static void changeData() {
zkClient.writeData("/java", "23456");
}
二、註冊中心
2.1 服務提供者啓動->註冊自己
2.2 服務消費者調用->獲取服務列表
2.3 性能問題
服務消費者每次調用時,都有從zk 上獲取一次數據
在高併發調用,每次去獲取遠程的服務列表,是個性能問題
若每次拉取服務要2 s -0s
遠程需要1 s
=3s->1s
2.4 緩存的思想
查詢數據:管理員的菜單
2.4 緩存的髒讀
緩存裏面的時間和數據源裏面的數據不一致導致
Eg: 現在有個服務掛了,zk 上會自動刪除它,但是緩存列表裏面還有它
若:zk 上節點有變化,能修改我的緩存(訂閱的功能)
/**
* 1 第一次從zk 上面拉取 ?
* 2 拉取之後保存起來
* 3 以後的獲取數據都從緩存裏面找
*
* @param serverName
* @return
*/
public static List<String>fetchServerListCache(String serverName){
if(serverList.containsKey(serverName)) { // 代表之前獲取過該服務的列表
System.out.println("從緩存裏面獲取");
List<String> list = serverList.get(serverName);
return list;
}
List<String> fetchServerList = fetchServerList(serverName); //不包含,說明之前沒有拉取過,我先拉取到,保存起來
serverList.put(serverName, fetchServerList);
// 拉取成功後,我開始關注這個節點,若該節點有變化,我修改緩存裏面的數據
zkClient.subscribeChildChanges("/"+serverName, new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
System.out.println("有服務死機或上線,需要更新服務的列表");
System.out.println("緩存裏面的服務列表爲"+serverList.get(serverName));
System.out.println("最新的爲"+currentChilds);
System.out.println("開始更新");
serverList.put(serverName, currentChilds);
System.out.println("修改成功");
}
});
return fetchServerList;
}