zookeeper实现节点动态上下线感知
节点动态上下线感知的实现原理
Zookeeper 是一个分布式协调服务,可以管理(存储、读取)用户程序提交的数据,并为用户程序提供数据节点监听服务。
节点动态上下线感知就是利用Zookeeper的节点监听功能,服务端程序上线时,在zookeeper上创建一个临时有序节点,临时节点具有当session不存在该节点就从Zookeeper上会自动删除的功能。
客户端程序一启动就监听Zookeeper上存放服务器创建临时节点的父节点,当父节点下的子节点有增加或者减少时,客户端程序的监听就会被回调,在回调方法中可以重新获取能提供服务的服务器节点信息。
具体实现
使用idea + maven开发
引入依赖
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
<!--<type>pom</type>-->
</dependency>
服务器端代码
package cn.zhou.bigdata.zkdist;
import org.apache.zookeeper.KeeperException;
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;
public class DistributedClient {
private static String connectionStr = "mini41:2181,mini42:2181,mini43:2181";
private static int sessionTimeOut = 2000;
private static ZooKeeper zkClient;
public static final String PARENT_NODE_NAME = "/servers";
private static volatile ArrayList<String> servers;
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// getChildren and register watcher
getConnection();
// get Available servers
getAvailableServers();
doBusiness();
}
public static void getConnection() throws IOException {
zkClient = new ZooKeeper(connectionStr, sessionTimeOut, new Watcher() {
public void process(WatchedEvent watchedEvent) {
try {
if (watchedEvent.getType() == Event.EventType.NodeChildrenChanged && PARENT_NODE_NAME.equals(watchedEvent.getPath())) {
getAvailableServers();
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
public static void getAvailableServers() throws KeeperException, InterruptedException {
ArrayList<String> serverList = new ArrayList<String>();
List<String> children = zkClient.getChildren(PARENT_NODE_NAME, true);
for (String child : children) {
byte[] data = zkClient.getData(PARENT_NODE_NAME + "/" + child, null, null);
serverList.add(new String(data));
}
servers = serverList;
System.out.println("The list of servers that can provide services is " + servers);
}
private static void doBusiness() throws InterruptedException {
System.out.println("do your business " + servers);
Thread.sleep(Integer.MAX_VALUE);
}
}
客户端代码
package cn.zhou.bigdata.zkdist;
import org.apache.zookeeper.KeeperException;
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;
public class DistributedClient {
private static String connectionStr = "mini41:2181,mini42:2181,mini43:2181";
private static int sessionTimeOut = 2000;
private static ZooKeeper zkClient;
public static final String PARENT_NODE_NAME = "/servers";
private static volatile ArrayList<String> servers;
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// getChildren and register watcher
getConnection();
// get Available servers
getAvailableServers();
doBusiness();
}
public static void getConnection() throws IOException {
zkClient = new ZooKeeper(connectionStr, sessionTimeOut, new Watcher() {
public void process(WatchedEvent watchedEvent) {
try {
if (watchedEvent.getType() == Event.EventType.NodeChildrenChanged && PARENT_NODE_NAME.equals(watchedEvent.getPath())) {
getAvailableServers();
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
public static void getAvailableServers() throws KeeperException, InterruptedException {
ArrayList<String> serverList = new ArrayList<String>();
List<String> children = zkClient.getChildren(PARENT_NODE_NAME, true);
for (String child : children) {
byte[] data = zkClient.getData(PARENT_NODE_NAME + "/" + child, null, null);
serverList.add(new String(data));
}
servers = serverList;
System.out.println("The list of servers that can provide services is " + servers);
}
private static void doBusiness() throws InterruptedException {
System.out.println("do your business " + servers);
Thread.sleep(Integer.MAX_VALUE);
}
}
运行结果
先启动zookeeper集群,然后分别运行DistributedServer和DistributedClient
启动DistributedServer,启动传入mini1
启动DistributedClient
再启动一个DistributedServer,模拟新的服务端程序上线操作,启动传入mini2
客户端已经获取到服务器
停掉mini1的服务器端
可以提供的服务器列表由[mini2,mini1]变成[mini2],目前只有mini2才能提供服务。