一、监听服务器节点动态上下线案例
- 需求:某分布式系统中,主节点可以有多台,可以动态上下线,任意一台客户端都能实时感知到主节点服务器的上下线。
- 需求分析:不管是服务器还是客户端,对于zookeeper而言都是客户端
服务器端代码:
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
public class DistributeServer {
// 模拟服务器上线(上线则在zookeeper上创建节点)
private static ZooKeeper zooKeeper;
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// 连接zookeeper
connectzkp();
// 创建节点
createNode("Hadoop01");
// 业务处理
doSomeThing();
}
private static void doSomeThing() throws InterruptedException {
/*
模拟服务器处理业务(目的是让当前客户端进程不被杀死)
客户端进程死了后,临时节点会被删除
*/
Thread.sleep(Long.MAX_VALUE);
}
/**
* 上线则在zookeeper上创建节点
* @param hostname :主机的名称
*/
private static void createNode(String hostname) throws KeeperException, InterruptedException {
/*
在servers下创建子节点,
这样方便管理,不过可以随便起节点名
*/
// 先判断servers节点是否存在
Stat exists = zooKeeper.exists("/servers", true);
if (exists == null){
// 不存在则创建/servers节点
String basePath = zooKeeper.create("/servers",
"sss".getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
/*
如果服务器上线,则在/servers创建子节点保存服务器信息
创建临时有序节点,模拟实现服务器与客户端断开连接,客户端能获取消息
*/
String chridPath = zooKeeper.create("/servers/" + "server",
hostname.getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
}
// 连接zooKeeper
private static void connectzkp() throws IOException {
/*
public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher) throws IOException {
this(connectString, sessionTimeout, watcher, false);}
String connectString :连接客户端信息
int sessionTimeout :
*/
String connect = "centos7-1:2181,centos7-2:2181,centos7-3:2181";
int sessionTimeout = 2000;
zooKeeper = new ZooKeeper(connect, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("执行回调方法");
System.out.println(watchedEvent.getPath());
}
});
}
}
客户端代码:
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class DistributeClient {
// 监听服务器的上下线
private static ZooKeeper zooKeeper;
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// 连接zookeeper的客户端
connectzkp();
/*
监听服务器的上下线
注册观察者
*/
register();
// 业务处理
doSomeThing();
}
private static void doSomeThing() throws InterruptedException {
Thread.sleep(Long.MAX_VALUE);
}
// 监听服务器的上下线,并注册观察者
private static void register() throws KeeperException, InterruptedException {
// 查询 /servers下的子节点,也就是上线服务器节点,并开启观察者
List<String> children = zooKeeper.getChildren("/servers", true);
// children包含的是服务器创建的节点信息
ArrayList<String> hosts = new ArrayList<>();
for (String child : children) {
// child :服务器节点的名称
byte[] data = zooKeeper.getData("/servers/" + child, false, new Stat());
//System.out.println(new String(data)+"在线");
hosts.add(new String(data));
}
// 打印上线的服务器名称
System.out.println(hosts);
}
// 连接zookeeper
private static void connectzkp() throws IOException {
/**
* String connectString, int sessionTimeout, Watcher watcher
*/
String connectString = "centos7-1:2181,centos7-2:2181,centos7-3:2181";
Integer sessionTimeout = 2000;
zooKeeper = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
// 观察者的回调方法
System.out.println(watchedEvent.getType());
System.out.println(watchedEvent.getPath());
try {
// 因为观察者接受到一次通知就被移除了,所以再次调用 register
// 完成再注册
register();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}