一、节点操作
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;
}