1.4.2 监听节点
ZooKeeper有两个类型的节点:持久和临时。另外,次序号是这个两个类型节点的修饰符。持久和临时节点都可以使用次序号修饰,表示这个节点是次序化的节点。
ZooKeeper是用Watch观察命名空间的节点状态变化,一旦有节点状态发生变化,客户端的Watch实例将得到通知(notify)。为了演示这个过程,下面有一个例子。
NodeMonitor类定义指定命名空间的监听,一旦有数据发生变化,它马上就能够得到通知。对于在线服务节点,这个监听能够实现有效服务的实时监控,以便为其它调用服务提供可靠的容错服务。另外, 根据在线服务的节点实现负载均衡。NodeClient是一个客户端,通过创建的客户端的进程号标识这个客户。
监听类NodeMonitor。
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.List;
/**
* @author john.grails@gmail.com
*/
public class NodeMonitor implements Runnable {
private Watcher connectionWatcher = null;
private Watcher childrenWatcher = null;
private ZooKeeper zk;
protected boolean alive = true;
public NodeMonitor() throws InterruptedException, IOException, KeeperException {
init();
}
public void init() throws IOException, KeeperException, InterruptedException{
//Define the connection watch ,which watches the connection event.
connectionWatcher = new Watcher() {
@Override
public void process(WatchedEvent event) {
if(event.getType() == Event.EventType.None &&
event.getState() == Event.KeeperState.SyncConnected) {
System.out.printf("\n connection watch output event: %s", event.toString());
}
}
};
//Children watcher listens the NodeChildrenChanged event.
childrenWatcher = new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.printf("\n childrenWatcher Received: %s", event.toString());
if (event.getType() == Event.EventType.NodeChildrenChanged) {
try {
//Get current list of child znode, reset the watch
List<String> children = zk.getChildren(DataConfig.MEMBERS.getPath(), this);
printLog("--------- Cluster Membership Change ---------");
//Update live service objects in really environment.
printLog("Members: " + children);
} catch (KeeperException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
alive = false;
throw new RuntimeException(e);
}
}
}
};
zk = new ZooKeeper(ZookeeperConf.HOST_PORT, 2000, connectionWatcher);
// Ensure the parent znode exists
if(zk.exists(DataConfig.MEMBERS.getPath(), false) == null) {
//Create the node.
zk.create(DataConfig.MEMBERS.getPath(),
"ClusterMonitorRoot".getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
// Set a watch on the parent znode
List<String> children = zk.getChildren(DataConfig.MEMBERS.getPath(),
childrenWatcher);
System.err.println("Members: " + children);
}
public synchronized void close() {
try {
zk.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void printLog (String message) {
System.out.printf("\n group members: %s", message);
}
@Override
public void run() {
try {
synchronized (this) {
while (alive) {
if(zk != null && childrenWatcher != null){
List<String> children = null;
try {
children = zk.getChildren(DataConfig.MEMBERS.getPath(), childrenWatcher);
System.err.println("init members: " + children);
} catch (KeeperException e) {
e.printStackTrace();
}
//wait util the other threads call notify (or notifyAll) method
wait();
}else{
System.out.printf(" init error, try again !");
Thread.sleep(1000);
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
} finally {
this.close();
}
}
public static void main(String[] args)
throws IOException, InterruptedException, KeeperException {
new NodeMonitor().run();
}
}
客户端NodeClient。
import org.apache.zookeeper.*;
import java.io.IOException;
import java.lang.management.ManagementFactory;
/**
* @author john.grails@gmail.com
*/
public class NodeClient implements Watcher, Runnable {
private ZooKeeper zk;
public NodeClient( Long pid) {
String processId = pid.toString();
try {
zk = new ZooKeeper(ZookeeperConf.HOST_PORT, 3000, this);
} catch (IOException e) {
e.printStackTrace();
}
if (zk != null) {
try {
zk.create(DataConfig.MEMBERS.getPath() + '/' + processId,
processId.getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL);
} catch (Exception e) {
e.printStackTrace();
}
}else{
System.err.println("--------------error when creating ZooKeeper instance");
}
}
/**
* Client watch method.
* @param event WatchedEvent outputs the event type and event received.
*/
@Override
public void process(WatchedEvent event) {
System.out.printf("\n NodeClient event type: %s, NodeClient Event Received: %s",
event.getType(),event.toString());
}
@Override
public void run() {
try {
synchronized (this) {
while (true) {
System.out.println("----running ....");
wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
} finally {
this.close();
}
}
public synchronized void close() {
try {
zk.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//Get the process id
String name = ManagementFactory.getRuntimeMXBean().getName();
System.out.printf("getRuntimeMXBean mame: %s", name);
int index = name.indexOf('@');
Long processId = Long.parseLong(name.substring(0, index));
new NodeClient( processId).run();
}
}
欢迎关注我的微信公众号