https://blog.csdn.net/USTC_Zn/article/details/54974982
主体思路:
服务器端:服务器上线、在zookeeper创建 临时的序列化结点
客户端:已启动getchildren 并注册监听 ,获取到当前在线服务器列表。
效果:
客户端能动态感知服务器上下线情况、并获取新的服务器列表
服务器端源码:
- package com.zn.zk1;
- import org.apache.zookeeper.CreateMode;
- import org.apache.zookeeper.WatchedEvent;
- import org.apache.zookeeper.Watcher;
- import org.apache.zookeeper.ZooDefs.Ids;
- import org.apache.zookeeper.ZooKeeper;
- public class DistributedServer {
- private static final String connectString = "zk01:2181,zk02:2181,zk03:2181";
- private static final int sessionTimeout = 2000;
- private static final String parentNode = "/servers";
- private ZooKeeper zk = null;
- /**
- * 模拟服务器上线
- * @param args
- * @throws Exception
- */
- public static void main(String[] args) throws Exception {
- // 获取zk连接
- DistributedServer server = new DistributedServer();
- server.getConnect();
- // 利用zk连接注册服务器信息
- server.registerServer(args[0]);
- // 启动业务功能
- server.handleBussiness(args[0]);
- }
- /**
- * 创建到zk的客户端连接
- *
- * @throws Exception
- */
- public void getConnect() throws Exception {
- zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
- public void process(WatchedEvent event) {
- // 收到事件通知后的回调函数(应该是我们自己的事件处理逻辑)
- System.out.println(event.getType() + "---" + event.getPath());
- try {
- zk.getChildren("/", true);
- } catch (Exception e) {
- }
- }
- });
- }
- /**
- * 向zk集群注册服务器信息
- *
- * @param hostname
- * @throws Exception
- */
- public void registerServer(String hostname) throws Exception {
- //运行时请手动创建父节点/servers
- //临时的临时的序列化结点
- String create = zk.create(parentNode + "/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
- System.out.println(hostname + "is online.." + create);
- }
- /**
- * 业务功能
- *
- * @throws InterruptedException
- */
- public void handleBussiness(String hostname) throws InterruptedException {
- System.out.println(hostname + "start working.....");
- Thread.sleep(Long.MAX_VALUE);
- }
- }
-----------------------华丽的分界线---------------------
客户端源码:
- package com.zn.zk1;
- import java.util.ArrayList;
- import java.util.List;
- import org.apache.zookeeper.KeeperException;
- import org.apache.zookeeper.WatchedEvent;
- import org.apache.zookeeper.Watcher;
- import org.apache.zookeeper.ZooKeeper;
- public class DistributedClient {
- private static final String connectString = "zk01:2181,zk02:2181,zk03:2181";
- private static final int sessionTimeout = 2000;
- private static final String parentNode = "/servers";
- /** 注意:加<span style="color:#ff0000;"><strong>volatile的意义</strong></span>何在?---serverList对象在JVM堆中,多线程时会对该对象进行更改,每个线程对该对象操作会
- * copy一个副本到本地线程栈,再对该对象进行修改操作,改完后,再将该对象同步到共享的堆内存中。
- * 被volatile修饰的对象则不会被copy到本地线程栈。所有线程看到的该对象是同一个。不会出现多线程问题。
- */
- private volatile List<String> serverList;
- private ZooKeeper zk = null;
- public static void main(String[] args) throws Exception {
- // 获取zk连接
- DistributedClient client = new DistributedClient();
- //创建zookeeper连接
- client.getConnect();
- // 获取servers的子节点信息(并监听),从中获取服务器信息列表
- client.getServerList();
- // 业务线程启动
- client.handleBussiness();
- }
- /**
- * 业务功能
- *
- * @throws InterruptedException
- */
- public void handleBussiness() throws InterruptedException {
- System.out.println("client start working.....");
- Thread.sleep(Long.MAX_VALUE);
- }
- /**
- * 创建到zk的客户端连接
- * @throws Exception
- */
- public void getConnect() throws Exception {
- zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
- public void process(WatchedEvent event) {
- // 收到事件通知后的回调函数(应该是我们自己的事件处理逻辑)
- try {
- //重新更新服务器列表,并且注册了监听
- getServerList();
- } catch (Exception e) {
- }
- }
- });
- }
- /**
- * 获取服务器信息列表
- *
- * @throws Exception
- */
- public void getServerList() throws Exception {
- // 获取服务器子节点信息,并且对父节点进行监听
- List<String> children = zk.getChildren(parentNode, true);
- // 先创建一个局部的list来存服务器信息
- List<String> servers = new ArrayList<String>();
- for (String child : children) {
- // child只是子节点的节点名
- byte[] data = zk.getData(parentNode + "/" + child, false, null);
- servers.add(new String(data));
- }
- // 把servers赋值给成员变量serverList,已提供给各业务线程使用
- serverList = servers;
- //打印服务器列表
- System.out.println(serverList);
- }
- }
最后:可以将两个java文件分别打包、部署到服务器测试、也可以在IDE上测试执行效果。
微信公众号: 架构师日常笔记 欢迎关注!