ZK有个很重要的一点就是监听,监听的策略是什么啊?下面看完详细描述:
ZK作为一个分布式协调者,比如A注册到ZK,B从ZK中拉取A的注册信息引用A,并且B从ZK服务端时刻监听A是否还存活着,如果A,发生了删除、修改操作,会立刻同步到ZK服务端,此时ZK服务端会回调B,告诉B服务A目前的情况。
1、客户端监听原理图:
此处监听和回调都是通过ZK服务器进行的,当然如果说ZK本身没有监听机制,我们可以直接心跳验证所引用的客户端服务,这就需要代码服务了,这就是监听的另一个方向,此方向的实效性不如ZK监听,因为ZK是直接回调客户端,二心跳验证一般是间隔几秒请求验证一次,实效性相对查一下。
1.1、如上图所示,第二个客户端首次回get到信息,然后启动监听watch,如果第一个客户端发生了改变,ZK会立刻回调第二个客户端,即谁监听它,就回调谁,实效性非常高。
1.2、心跳验证是我们假象的一种实现监听的方案。
2、代码演示:刚开始只有一个默认节点:
业务代码测试:
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.util.concurrent.CountDownLatch;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args ) throws Exception {
System.out.println( "Hello World!" );
//zk是有session概念的,没有连接池的概念
//watch:观察,回调
//watch的注册值发生在 读类型调用,get,exites。。。
//第一类:new zk 时候,传入的watch,这个watch,session级别的,跟path 、node没有关系。
final CountDownLatch cd = new CountDownLatch(1);
final ZooKeeper zk = new ZooKeeper("192.168.150.11:2181,192.168.150.12:2181,192.168.150.13:2181,192.168.150.14:2181",
3000, new Watcher() {
//Watch 的回调方法!
@Override
public void process(WatchedEvent event) {
Event.KeeperState state = event.getState();
Event.EventType type = event.getType();
String path = event.getPath();
System.out.println("new zk watch: "+ event.toString());
switch (state) {
case Unknown:
break;
case Disconnected:
break;
case NoSyncConnected:
break;
case SyncConnected:
System.out.println("connected");
cd.countDown();
break;
case AuthFailed:
break;
case ConnectedReadOnly:
break;
case SaslAuthenticated:
break;
case Expired:
break;
}
switch (type) {
case None:
break;
case NodeCreated:
break;
case NodeDeleted:
break;
case NodeDataChanged:
break;
case NodeChildrenChanged:
break;
}
}
});
cd.await();
ZooKeeper.States state = zk.getState();
switch (state) {
case CONNECTING:
System.out.println("ing......");
break;
case ASSOCIATING:
break;
case CONNECTED:
System.out.println("ed........");
break;
case CONNECTEDREADONLY:
break;
case CLOSED:
break;
case AUTH_FAILED:
break;
case NOT_CONNECTED:
break;
}
String pathName = zk.create("/ooxx", "olddata".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
final Stat stat=new Stat();
byte[] node = zk.getData("/ooxx", new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println("getData watch: "+event.toString());
try {
//true default Watch 被重新注册 new zk的那个watch
zk.getData("/ooxx",this ,stat);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, stat);
System.out.println(new String(node));
//触发回调
Stat stat1 = zk.setData("/ooxx", "newdata".getBytes(), 0);
//还会触发吗?
Stat stat2 = zk.setData("/ooxx", "newdata01".getBytes(), stat1.getVersion());
System.out.println("-------async start----------");
zk.getData("/ooxx", false, new AsyncCallback.DataCallback() {
@Override
public void processResult(int rc, java.lang.String path, Object ctx, byte[] data, Stat stat) {
System.out.println("-------async call back----------");
System.out.println(ctx.toString());
System.out.println(new String(data));
}
},"abc");
System.out.println("-------async over----------");
Thread.sleep(2222222);
}
}
执行结果:
业务代码执行之后,服务器状态:
停留三秒钟就消失了。
因此,可以充分证明ZK的监听原理,到此分析完毕,下一篇我们分析ZK的配置和分布式锁的原理和实战,敬请期待!