需求
某分布式系统中,主节点可以有多台,可以动态上下线,任意一台客户端都能实时感知到主节点服务器的上下线。
需求分析

具体实现
先在集群上创建
/servers节点[zk: localhost:2181(CONNECTED) 7] create /servers "servers"Created /servers
在Idea中创建包名:
com.zh.zhcase1- 服务器端向Zookeeper注册代码 ```java package com.zh.zkcase1;
import org.apache.zookeeper.*;
import java.io.IOException;
/**
- author: zhanghui
- project: big-data-learning
- package: com.zh.zkcase1
- filename: DistributeServer
- date: 2022/2/28 14:29
description: 服务器端向Zookeeper注册 */ public class DistributeServer { private static String connectString = “linux102:2181,linux103:2181,linux104:2181”; private static int sessionTimeout = 2000; private ZooKeeper zk = null; private String parentNode = “/servers”;
// 创建到zk的客户端连接 public void getConnect() throws IOException {
zk = new ZooKeeper(connectString, sessionTimeout, event -> System.out.println(event.getType() + "---" + event.getPath()));}
// 注册服务器 public void registerServer(String hostname) throws Exception {
String create = zk.create(parentNode + "/server", hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println(hostname + " is online " + create);}
// 业务功能 public void business(String hostname) throws Exception {
System.out.println(hostname + " is working..."); Thread.sleep(Long.MAX_VALUE);}
public static void main(String[] args) throws Exception {
// 1. 获取Zk连接 DistributeServer server = new DistributeServer(); server.getConnect(); // 2. 利用Zk连接注册服务器信息 server.registerServer(args[0]); // 3. 启动业务功能 server.business(args[0]);} } ```
- 客户端代码 ```java package com.zh.zkcase1;
import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper;
import java.io.IOException; import java.util.ArrayList; import java.util.List;
/**
- author: zhanghui
- project: big-data-learning
- package: com.zh.zkcase1
- filename: DistributeClient
- date: 2022/2/28 14:50
description: zk客户端 */ public class DistributeClient { private static String connectString = “linux102:2181,linux103:2181,linux104:2181”; private static int sessionTimeout = 2000; private ZooKeeper zk = null; private String parentNode = “/servers”;
// 创建到zk的客户端连接 public void getConnect() throws IOException {
new ZooKeeper(connectString, sessionTimeout, event -> { System.out.println(event.getType() + "---" + event.getPath()); // 再次启动监听 try { getServerList(); } catch (Exception e) { e.printStackTrace(); } });}
// 获取服务器列表信息 public void getServerList() throws Exception {
// 1. 获取服务器子节点信息,并且对父节点进行监听 List<String> children = zk.getChildren(parentNode, true); // 2. 存储服务器信息列表 ArrayList<String> servers = new ArrayList<>(); // 3. 遍历所有节点,获取节点中的主机名称信息 for (String child : children) { byte[] data = zk.getData(parentNode + "/" + child, false, null); servers.add(new String(data)); } // 4. 打印服务器列表信息 System.out.println(servers);}
// 业务功能 public void business() throws Exception {
System.out.println("client is working..."); Thread.sleep(Long.MAX_VALUE);}
public static void main(String[] args) throws Exception {
// 1. 获取ZK连接 DistributeClient client = new DistributeClient(); client.getConnect(); // 2. 获取servers的子节点信息,从中获取服务器信息列表 client.getServerList(); // 3. 业务进程启动 client.business();} } ```
测试
在linux命令行上操作增加减少服务器
- 启动DistributeClient客户端
在linux102上ZK的客户端
/servers目录上创建临时带序号节点[zk: localhost:2181(CONNECTED) 8] create -e -s /servers/linux102 "linux102" Created /servers/linux1020000000000 [zk: localhost:2181(CONNECTED) 9] create -e -s /servers/linux103 "linux103" Created /servers/linux1030000000001观察idea控制台
NodeChildrenChanged---/servers [linux102, linux103]执行删除操作
[zk: localhost:2181(CONNECTED) 10] delete /servers/linux1020000000000观察idea控制台变化
NodeChildrenChanged---/servers [linux103]
在IDEA上操作增加减少服务器
- 启动DistributeClient客户端(如果已经启动过,不需要启动)
- 启动DistributeServer服务
- 点击Edit Configurations…

2. 在弹出的窗口中(Program arguments)输入想启动的主机,例如,linux102

3. 回到DistributeServer的main方法,右键,在弹出的窗口中点击`Run "DistributeServer.main()"`
4. 观察DistributeServer控制台,提示`linux102 is working...`
4. 观察DistributeClient控制台,提示`[linux102, linux103]`
