某分布式系统中,主节点可以有多台,可以动态上下线,任意一台客户端都能实时感知到主节点服务器上下线的变化
1.需求分析
- 无论是服务器端,还是客户端,相对于zookeeper集群来说“都是客户端”,服务器端的“客户端”向zookeeper集群中写数据,客户端的“客户端”监听写在zookeeper集群上的数据的变化
- 服务器端启动时去注册信息【创建的都是临时节点】
- 客户端启动就getChildren(),获取到当前服务器列表,并且注册监听
- 当某一服务器下线时,zookeeper集群中该服务器对应的节点消失
- 服务器节点上下线事件通知,告知注册监听者
- 注册监听者采取相应措施,执行process()进程【重新获取服务器列表,并且注册监听】
2.具体实现
- 启动zookeeper集群
bin/zkServer.sh start
bin/zkCli.sh
- 在集群上创建/servers节点
create /servers "servers"
- 服务器端向zookeeper注册代码
public class DistributeServer {
public static void main(String[] args) throws Exception {
DistributeServer server = new DistributeServer();
// 1.连接zookeeper集群
server.getConnect();
// 2.注册节点
// args传入hostname,即看启动几次
server.regist(args[0]);
// 3.业务逻辑代码
server.business();
}
private void business() throws InterruptedException {
// 延时阻塞,为了使进程不结束
Thread.sleep(Long.MAX_VALUE);
}
private void regist(String hostname) throws KeeperException, InterruptedException {
String path = zkClient.create("/servers/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(hostname + " is online!");
}
private String connectString = "192.168.1.10:2181,192.168.1.11:2181,192.168.1.12:2181";
private int sessionTimeout = 2000;
private ZooKeeper zkClient;
private void getConnect() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent event) {
}
});
}
}
带序号【-s】的临时【-e】节点
- 客户端代码
public class DistributeClient {
public static void main(String[] args) throws Exception {
DistributeClient client = new DistributeClient();
// 1.连接zookeeper集群
client.getConnect();
// 2.注册监听
client.getChildren();
// 3.业务逻辑处理
client.business();
}
private void business() throws InterruptedException {
Thread.sleep(Long.MAX_VALUE);
}
private void getChildren() throws KeeperException, InterruptedException {
List<String> children = zkClient.getChildren("/servers", true);
// 存储服务器节点主机名称
ArrayList<String> hosts = new ArrayList<String>();
for (String child : children) {
byte[] data = zkClient.getData("/servers/" + child, false, null);
hosts.add(new String(data));
}
// 将所有在线主机名称打印到控制台
System.out.println(hosts);
}
private String connectString = "192.168.1.10:2181,192.168.1.11:2181,192.168.1.12:2181";
private int sessionTimeout = 2000;
private ZooKeeper zkClient;
private void getConnect() throws IOException {
// 放到watcher里面死循环,可以多次执行:一直监听动态节点的变化
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent event) {
try {
getChildren();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}