本节介绍
最近比较忙又加上十一假期,有段时间没有写博客了,今天继续哈。。。。。。
本节会介绍一下zookeeper的watcher机制,并且会写出对应的代码示例进行演示。
zookeeper的watcher介绍
zookeeper的事件监听
通过zookeeper系列的首节介绍,我们知道zookeeper主要用来做配置管理、集群管理、资源抢占协调等,而这些功能的都依赖于zookeeper的监听及通知机制
zookeeper中的事件类型及连接状态介绍
public ZookeeperBase(String connectString,int sessionTimeout) throws IOException{
this.connectString=connectString;
this.sessionTimeout=sessionTimeout;
zookeeper=new ZooKeeper(this.connectString, this.sessionTimeout, new Watcher() {
public void process(WatchedEvent event) {
//影响的路径
String path = event.getPath();
//获取连接的状态
KeeperState state = event.getState();
//获取事件的类型
EventType type = event.getType();
if(KeeperState.SyncConnected.equals(state)){
if(EventType.None.equals(type)){
//连接建立成功,则释放信号量,让阻塞的程序继续向下执行
countDown.countDown();
logger.info("zk建立连接成功========");
}
}
}
});
}
还记得上一节介绍zookeeper的java api连接服务的代码吗,里面其实已经用到了zookeeper的watcher,里面有两个特别关键的类:KeeperState(连接状态)和EventType(事件类型)
通过查看源码得知,这两个类都是Watcher接口的内部接口Event的内部枚举类。
/**
* This interface defines the possible states an Event may represent
*/
public interface Event {
/**
* Enumeration of states the ZooKeeper may be at the event
*/
public enum KeeperState {
/** The client is in the disconnected state - it is not connected
* to any server in the ensemble. */
Disconnected (0),
/** The client is in the connected state - it is connected
* to a server in the ensemble (one of the servers specified
* in the host connection parameter during ZooKeeper client
* creation). */
SyncConnected (3),
/**
* Auth failed state
*/
AuthFailed (4),
/**
* The client is connected to a read-only server, that is the
* server which is not currently connected to the majority.
* The only operations allowed after receiving this state is
* read operations.
* This state is generated for read-only clients only since
* read/write clients aren't allowed to connect to r/o servers.
*/
ConnectedReadOnly (5),
/**
* SaslAuthenticated: used to notify clients that they are SASL-authenticated,
* so that they can perform Zookeeper actions with their SASL-authorized permissions.
*/
SaslAuthenticated(6),
/** The serving cluster has expired this session. The ZooKeeper
* client connection (the session) is no longer valid. You must
* create a new client connection (instantiate a new ZooKeeper
* instance) if you with to access the ensemble. */
Expired (-112);
}
/**
* Enumeration of types of events that may occur on the ZooKeeper
*/
public enum EventType {
None (-1),
NodeCreated (1),
NodeDeleted (2),
NodeDataChanged (3),
NodeChildrenChanged (4);
}
}
上面贴出了两个枚举类的主要的源码片段(去掉了KeeperState中的被标记为@Deprecated的连接状态以及一些其他判断代码),下面我们来对相应的连接状态及事件类型做一个介绍。
zookeeper客户端与服务端连接的状态
连接状态 | 描述 |
---|---|
KeeperState.Disconnected | 当客户端断开连接(与集群中的任何一台断开连接)时的状态就是Disconnected |
KeeperState.SyncConnected | 当客户端与zookeeper集群中的任意一台建立连接,这时的事件状态就是SyncConnected |
KeeperState.AuthFailed | 客户端进行连接认证失败时,事件状态为AuthFailed |
KeeperState.ConnectedReadOnly | 当前客户端连接到的zookeeper服务是只读的,此时事件状态是ConnectedReadOnly,这时的客户端只可以进行读操作,而不能进行写操作 |
KeeperState.SaslAuthenticated | 用于通知客户端它们是SASL认证的 |
KeeperState.Expired | 客户端与zookeeper服务端建立连接后每隔一定时间会发送一次心跳检测,当心跳检测没有收到服务端的响应时即认定断开连接,session失效,此时的事件状态就是Expired,如果客户端想访问服务端,需要重新建立连接。 |
注意:zookeeper上述状态在触发时,所记录的事件类型都是:EventType.None
zookeeper中的事件,当客户端监听某个节点“/test”时
zookeeper事件 | 描述 |
---|---|
EventType.NodeCreated | 当test这个节点被创建时,该事件被触发 |
EventType.NodeChildrenChanged | 当test这个节点的直接子节点被创建、被删除、子节点数据发生变更时,该事件被触发 |
EventType.NodeDataChanged | 当test这个节点的数据发生变更时,该事件被触发 |
EventType.NodeDeleted | 当test这个节点被删除时,该事件被触发 |
EventType.None | 当zookeeper客户端的连接状态发生变更时(上面连接状态表格中所列),描述的事件类型为EventType.None |
zookeeper中的watcher
zookeeper中给节点添加watcher的方式有两种:
- 使用默认的watcher:ZooKeeper.getData(path, watcher, stat), ZooKeeper.getChildren(path, watch),ZooKeeper.exists(String path, boolean watch),exists方法中watch==true时使用的就是默认的watcher,而默认的watcher是怎么添加的呢?其实我们在之前的代码中已经用到过,zookeeper创建连接的构造方法 ZooKeeper(String connectString, int sessionTimeout, Watcher watcher)中可以添加一个watcher,而这个watcher就是默认的watcher,另外ZooKeeper.register(Watcher watcher)也可以注册默认的watcher
-
给节点指定的watcher:使用类似ZooKeeper.exists(String path, Watcher watcher)这种方法可以给节点指定watcher
上面贴出了部分源码,我们可以看到exists(String path,boolean watch)中如果watch==true则会使用默认的watcher。
注意:
- 1:同一个watcher实例被例如exists,getData等方法多次注册,zookeeper客户端也只会收到一次通知
- 2:当一个节点注册多个不同的watcher实例时,会通知多次,即每个被注册的watcher都会收到通知
- 3:zk.getData(“/node-x”,watcher)这种注册方式不能监控节点的NodeCreated事件。当一个节点还不存在时,zk.getData这样设置的watcher是会抛出KeeperException$NoNodeException异常的,这次注册会失败,watcher也不会起作用;一旦node-x节点存在了,那这个节点的NodeCreated事件就不会存在了。。。
下面列一个表格,说明一个“/test”节点用不同的注册watcher的方法与可监听事件的关系
注册方式 | NodeCreated | NodeChildrenChanged | NodeDataChanged | NodeDeleted |
---|---|---|---|---|
zk.getChildren(“/test”,watcher) | 可监控 | 可监控 | ||
zk.exists(“/test”,watcher) | 可监控 | 可监控 | 可监控 | |
zk.getData(“/test”,watcher) | 可监控 | 可监控 |
zookeeper的watcher测试
下面我们用一个demo程序,测试一下我们上面的关于watcher的描述。废话不说,直接上代码
package com.wkp.test.zookeeper.watcher;
import java.util.concurrent.CountDownLatch;
import org.apache.log4j.Logger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import com.wkp.test.zookeeper.base.ZookeeperBase;
public class TestZookeeperWatcher{
private static Logger logger=Logger.getLogger(ZookeeperBase.class);
/** 信号量,阻塞程序执行,用于等待zookeeper连接成功,发送成功信号 */
private CountDownLatch countDown=new CountDownLatch(1);
public void test(){
ManyWatcherDefault defaultWatcher = new ManyWatcherDefault(countDown);
ZooKeeper zkClient=null;
try {
zkClient=new ZooKeeper("192.168.74.4:2181,192.168.74.5:2181,192.168.74.6:2181",10000,defaultWatcher);
//建立连接之前一直阻塞
countDown.await();
} catch (Exception e) {
e.printStackTrace();
}
logger.info("=====实验1测试同一个节点注册多个监听=======");
String path="/test";
ManyWatcherA a = new ManyWatcherA(zkClient, path);
ManyWatcherB b = new ManyWatcherB(zkClient, path);
try {
//此时/test节点不存在,下面两个方法都是返回null
zkClient.exists(path, a);
zkClient.exists(path, b);
//下面创建/test节点,会触发A,B两个监听
zkClient.create(path, "testValue".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
} catch (Exception e) {
e.printStackTrace();
return;
}
logger.info("=====实验2测试getData()方法注册监听,NodeCreated是否可以监听到=====");
path="/test222";
ManyWatcherA a22 = new ManyWatcherA(zkClient, path);
ManyWatcherB b22 = new ManyWatcherB(zkClient, path);
try {
zkClient.getData(path, a22, null);
zkClient.getData(path, b22, null);
//下面创建/test222节点,测试监听a22,b22是否被触发
zkClient.create(path, "test222Value".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
/**
* 这是默认的watcher实现。
*/
static class ManyWatcherDefault implements Watcher {
private static final Logger logger=Logger.getLogger(ManyWatcherDefault.class);
private CountDownLatch countDown;
public ManyWatcherDefault(CountDownLatch countDown){
this.countDown=countDown;
}
public void process(WatchedEvent event) {
KeeperState keeperState = event.getState();
EventType eventType = event.getType();
if(KeeperState.SyncConnected.equals(keeperState)){
if(EventType.None.equals(eventType)){
//连接建立成功,则释放信号量,让阻塞的程序继续向下执行
countDown.countDown();
logger.info("=========默认监听到None事件:keeperState = "
+ keeperState + " : eventType = " + eventType);
}
}
}
}
static class ManyWatcherA implements Watcher {
private static final Logger logger=Logger.getLogger(ManyWatcherA.class);
private ZooKeeper zkClient;
/** 监控的路径 */
private String watchPath;
public ManyWatcherA(ZooKeeper zkClient,String watchPath){
this.zkClient=zkClient;
this.watchPath=watchPath;
}
public void process(WatchedEvent event) {
try {
zkClient.exists(watchPath, this);
} catch (Exception e) {
e.printStackTrace();
}
KeeperState keeperState = event.getState();
EventType eventType = event.getType();
//当前事件发生的path
String path = event.getPath();
logger.info("=========ManyWatcherA监听到"+path+"地址发生事件:keeperState = "
+ keeperState + " : eventType = " + eventType);
}
}
static class ManyWatcherB implements Watcher {
private static final Logger logger=Logger.getLogger(ManyWatcherB.class);
private ZooKeeper zkClient;
/** 监控的路径 */
private String watchPath;
public ManyWatcherB(ZooKeeper zkClient,String watchPath){
this.zkClient=zkClient;
this.watchPath=watchPath;
}
public void process(WatchedEvent event) {
try {
zkClient.exists(watchPath, this);
} catch (Exception e) {
e.printStackTrace();
}
KeeperState keeperState = event.getState();
EventType eventType = event.getType();
//当前事件发生的path
String path = event.getPath();
logger.info("=========ManyWatcherB监听到"+path+"地址发生事件:keeperState = "
+ keeperState + " : eventType = " + eventType);
}
}
public static void main(String[] args) {
TestZookeeperWatcher t = new TestZookeeperWatcher();
t.test();
}
}
运行上面的程序,可以看到下面控制台的关键日志
2018-10-14 17:14:08,239 main [zookeeper.ZooKeeper] 438 [INFO ] Initiating client connection, connectString=192.168.74.4:2181,192.168.74.5:2181,192.168.74.6:2181 sessionTimeout=10000 watcher=com.wkp.test.zookeeper.watcher.TestZookeeperWatcher$ManyWatcherDefault@2a8f7943
2018-10-14 17:14:08,350 main-SendThread(192.168.74.4:2181) [zookeeper.ClientCnxn] 975 [INFO ] Opening socket connection to server 192.168.74.4/192.168.74.4:2181. Will not attempt to authenticate using SASL (unknown error)
2018-10-14 17:14:08,355 main-SendThread(192.168.74.4:2181) [zookeeper.ClientCnxn] 852 [INFO ] Socket connection established to 192.168.74.4/192.168.74.4:2181, initiating session
2018-10-14 17:14:08,381 main-SendThread(192.168.74.4:2181) [zookeeper.ClientCnxn] 1235 [INFO ] Session establishment complete on server 192.168.74.4/192.168.74.4:2181, sessionid = 0x6671d96d200001, negotiated timeout = 10000
2018-10-14 17:14:08,385 main [base.ZookeeperBase] 34 [INFO ] =====实验1测试同一个节点注册多个监听=======
2018-10-14 17:14:08,385 main-EventThread [watcher.TestZookeeperWatcher$ManyWatcherDefault] 83 [INFO ] =========默认监听到None事件:keeperState = SyncConnected : eventType = None
2018-10-14 17:14:08,427 main [base.ZookeeperBase] 49 [INFO ] =====实验2测试getData()方法注册监听,NodeCreated是否可以监听到=====
2018-10-14 17:14:08,448 main-EventThread [watcher.TestZookeeperWatcher$ManyWatcherA] 112 [INFO ] =========ManyWatcherA监听到/test地址发生事件:keeperState = SyncConnected : eventType = NodeCreated
2018-10-14 17:14:08,459 main-EventThread [watcher.TestZookeeperWatcher$ManyWatcherB] 139 [INFO ] =========ManyWatcherB监听到/test地址发生事件:keeperState = SyncConnected : eventType = NodeCreated
org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for /test222
at org.apache.zookeeper.KeeperException.create(KeeperException.java:111)
at org.apache.zookeeper.KeeperException.create(KeeperException.java:51)
at org.apache.zookeeper.ZooKeeper.getData(ZooKeeper.java:1155)
at com.wkp.test.zookeeper.watcher.TestZookeeperWatcher.test(TestZookeeperWatcher.java:54)
at com.wkp.test.zookeeper.watcher.TestZookeeperWatcher.main(TestZookeeperWatcher.java:146)
通过运行结果,我们可以看到"/test"节点注册的默认watcher,watcherA,watcherB都被触发了,而"/test222"节点在不存在时调用getData()方法报了异常,由此我们可以得知:
1:对于同一个节点发生的事件,如果注册的是同一实例,用不同的方法注册多次,通知也只会发生一次;如果注册了多个不同的监听实例,会发起多次通知
2:对于不存在的节点,使用getData方法去注册监听,想获取节点创建事件,会报KeeperErrorCode = NoNode异常
上面已经给大家演示了zookeeper的watcher的用法,其他的事件您可以参照上面的示例自己进行测试,这里就不做过多的演示了。下面利用zookeeper的watcher来实现一个简单的分布式配置中心,以此说明一下watcher在实际当中的一个应用示例。
zookeeper的watcher应用示例:分布式配置中心
在实际的应用系统当中,经常会有一些需要变动的配置参数,比如某个功能的开关switch,我们根据switch=ON/OFF来绝对某个功能是开启还是关闭。我们经常会把这样的配置放在一个properties配置文件中,但是这样修改开关的时候就必须重启系统,这样就很不灵活,特别是当系统集群部署的时候,需要一个一个的去改,很麻烦!这个时候我们可以把这个switch开关放到zookeeper当中,集群中的每一个server都注册一个watcher去监听这个节点,这样当我们改变了switch的值的时候,集群中的每一台server都可以监听到变化,我们修改开关就可以很快的生效了,而且是一处修改,全部生效。
下面我们给出一个具体的demo示例,可以更清楚zookeeper在分布式配置当中的用法
package com.wkp.test.zookeeper.watcher.cluster;
import java.util.concurrent.CountDownLatch;
import org.apache.log4j.Logger;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
public class DistributedConfig implements Watcher{
private static Logger logger=Logger.getLogger(DistributedConfig.class);
//此处用了单例,为了应用程序只连接一次zookeeper的server端
@SuppressWarnings("unused")
private static DistributedConfig config=new DistributedConfig();
/** zk变量 */
private ZooKeeper zk = null;
/** 开关节点path */
private static final String switchNode = "/switch";
/** 开关值 ON/OFF */
private static String switchNodeValue = "DEFAULT";
/** 信号量设置,用于等待zookeeper连接建立之后 通知阻塞程序继续向下执行 */
private static CountDownLatch connectedSemaphore = new CountDownLatch(1);
private DistributedConfig() {
try {
zk = new ZooKeeper("192.168.74.4:2181,192.168.74.5:2181,192.168.74.6:2181",10000, this);
logger.info("开始连接ZK服务器");
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getSwitchNodeValue() throws InterruptedException{
//连接上zookeeper的server之前一直阻塞
connectedSemaphore.await();
return switchNodeValue;
}
@Override
public void process(WatchedEvent event) {
//获取事件的状态
KeeperState keeperState = event.getState();
EventType eventType = event.getType();
//如果是建立连接
if(KeeperState.SyncConnected == keeperState){
if(EventType.None == eventType){
//如果建立连接成功,则发送信号量,让后续阻塞程序向下执行
try {
Stat stat = this.zk.exists(switchNode, true);
//判断"/switch"节点存在的时候再getData()给变量赋值,否则会出现"NoNode for /switch" 的异常
if(stat!=null){
//给开关赋值并添加监听
switchNodeValue=new String(this.zk.getData(switchNode, true, null));
}
connectedSemaphore.countDown();
logger.info("zk 建立连接====================");
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
}else if (EventType.NodeCreated == eventType) {
try {
logger.info("节点创建================");
//给开关变量赋值并添加监听
switchNodeValue=new String(this.zk.getData(switchNode, true, null));
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
} else if (EventType.NodeDataChanged == eventType) {
try {
logger.info("节点数据更新==============");
//修改开关变量的值并添加监听
switchNodeValue=new String(this.zk.getData(switchNode, true, null));
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
DistributedConfig类是一个watcher,里面监听了一个"/switch"节点的状态:当创建连接的时候,如果"/switch"节点存在,则获取该节点的值并赋值给switchNodeValue属性;当节点创建了,则获取节点的值赋值给switchNodeValue属性;当节点更新了,则获取节点变更后的值赋值给switchNodeValue属性。
public class Client1 {
public static void main(String[] args) throws Exception{
//模拟server1的请求不断进来,查询开关状态
while(true){
System.out.println("server1服务器===============================");
Thread.sleep(10000);
System.out.println("switchNodeValue:"+DistributedConfig.getSwitchNodeValue());
}
}
}
public class Client2 {
public static void main(String[] args) throws Exception{
//模拟server2的请求不断进来,查询开关状态
while(true){
System.out.println("server2服务器*******************************");
Thread.sleep(10000);
System.out.println("switchNodeValue:"+DistributedConfig.getSwitchNodeValue());
}
}
}
Client1,Client2两个类模拟两台应用服务器,去连接zookeeper的server端,不停的监听并获取开关的状态值,两个Client
分别启动之后,通过zookeeper的zkCli.sh客户端工具操作 /switch 节点,然后观察控制台的日志变化。
Client1控制台关键输出如下
server1服务器===============================
2018-10-24 23:54:21,294 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:zookeeper.version=3.4.6-1569965, built on 02/20/2014 09:09 GMT
2018-10-24 23:54:21,300 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:host.name=USER-20150608SC
2018-10-24 23:54:21,301 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.version=1.7.0_25
2018-10-24 23:54:21,302 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.vendor=Oracle Corporation
2018-10-24 23:54:21,303 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.home=D:\wyonline\java\jdk1.7.0_25\jre
2018-10-24 23:54:21,304 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.class.path=D:\wyonline\myworkspaces\framework\zkTest\target\classes;D:\maven\.m2\repository\org\apache\zookeeper\zookeeper\3.4.6\zookeeper-3.4.6.jar;D:\maven\.m2\repository\org\slf4j\slf4j-api\1.6.1\slf4j-api-1.6.1.jar;D:\maven\.m2\repository\org\slf4j\slf4j-log4j12\1.6.1\slf4j-log4j12-1.6.1.jar;D:\maven\.m2\repository\jline\jline\0.9.94\jline-0.9.94.jar;D:\maven\.m2\repository\junit\junit\3.8.1\junit-3.8.1.jar;D:\maven\.m2\repository\io\netty\netty\3.7.0.Final\netty-3.7.0.Final.jar;D:\maven\.m2\repository\log4j\log4j\1.2.15\log4j-1.2.15.jar;D:\maven\.m2\repository\javax\mail\mail\1.4\mail-1.4.jar;D:\maven\.m2\repository\javax\activation\activation\1.1\activation-1.1.jar;D:\maven\.m2\repository\javax\jms\jms\1.1\jms-1.1.jar;D:\maven\.m2\repository\com\sun\jdmk\jmxtools\1.2.1\jmxtools-1.2.1.jar;D:\maven\.m2\repository\com\sun\jmx\jmxri\1.2.1\jmxri-1.2.1.jar
2018-10-24 23:54:21,305 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.library.path=D:\wyonline\java\jdk1.7.0_25\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;D:/wyonline/java8/jre1.8.0_181/bin/server;D:/wyonline/java8/jre1.8.0_181/bin;D:/wyonline/java8/jre1.8.0_181/lib/amd64;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;D:\wyonline\java\jdk1.8.0_181\bin;D:\wyonline\java\jdk1.8.0_181\jre\bin;D:\wyonline\apache-maven-3.1.0\bin;D:\wyonline\newMysql\bin;C:\Program Files (x86)\Rational\common;D:\Program Files\TortoiseSVN\bin;D:\wyonline\eclipse;;.
2018-10-24 23:54:21,305 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.io.tmpdir=C:\Users\ADMINI~1.USE\AppData\Local\Temp\
2018-10-24 23:54:21,306 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.compiler=<NA>
2018-10-24 23:54:21,307 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:os.name=Windows 7
2018-10-24 23:54:21,307 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:os.arch=amd64
2018-10-24 23:54:21,308 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:os.version=6.1
2018-10-24 23:54:21,309 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:user.name=Administrator
2018-10-24 23:54:21,309 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:user.home=C:\Users\Administrator.USER-20150608SC
2018-10-24 23:54:21,310 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:user.dir=D:\wyonline\myworkspaces\framework\zkTest
2018-10-24 23:54:21,312 main [zookeeper.ZooKeeper] 438 [INFO ] Initiating client connection, connectString=192.168.74.4:2181,192.168.74.5:2181,192.168.74.6:2181 sessionTimeout=10000 watcher=com.wkp.test.zookeeper.watcher.cluster.DistributedConfig@bcaeccf
2018-10-24 23:54:21,391 main [cluster.DistributedConfig] 36 [INFO ] 开始连接ZK服务器
2018-10-24 23:54:21,399 main-SendThread(192.168.74.5:2181) [zookeeper.ClientCnxn] 975 [INFO ] Opening socket connection to server 192.168.74.5/192.168.74.5:2181. Will not attempt to authenticate using SASL (unknown error)
2018-10-24 23:54:21,404 main-SendThread(192.168.74.5:2181) [zookeeper.ClientCnxn] 852 [INFO ] Socket connection established to 192.168.74.5/192.168.74.5:2181, initiating session
2018-10-24 23:54:21,472 main-SendThread(192.168.74.5:2181) [zookeeper.ClientCnxn] 1235 [INFO ] Session establishment complete on server 192.168.74.5/192.168.74.5:2181, sessionid = 0x166a6a1c8510007, negotiated timeout = 10000
switchNodeValue:DEFAULT
server1服务器===============================
2018-10-24 23:54:21,490 main-EventThread [cluster.DistributedConfig] 65 [INFO ] zk 建立连接====================
2018-10-24 23:54:31,328 main-EventThread [cluster.DistributedConfig] 71 [INFO ] 节点创建================
switchNodeValue:ON
server1服务器===============================
switchNodeValue:ON
server1服务器===============================
2018-10-24 23:54:49,252 main-EventThread [cluster.DistributedConfig] 79 [INFO ] 节点数据更新==============
switchNodeValue:OFF
server1服务器===============================
switchNodeValue:OFF
server1服务器===============================
switchNodeValue:OFF
Client2控制台关键输出如下
server2服务器*******************************
2018-10-24 23:54:25,816 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:zookeeper.version=3.4.6-1569965, built on 02/20/2014 09:09 GMT
2018-10-24 23:54:25,822 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:host.name=USER-20150608SC
2018-10-24 23:54:25,823 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.version=1.7.0_25
2018-10-24 23:54:25,824 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.vendor=Oracle Corporation
2018-10-24 23:54:25,825 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.home=D:\wyonline\java\jdk1.7.0_25\jre
2018-10-24 23:54:25,826 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.class.path=D:\wyonline\myworkspaces\framework\zkTest\target\classes;D:\maven\.m2\repository\org\apache\zookeeper\zookeeper\3.4.6\zookeeper-3.4.6.jar;D:\maven\.m2\repository\org\slf4j\slf4j-api\1.6.1\slf4j-api-1.6.1.jar;D:\maven\.m2\repository\org\slf4j\slf4j-log4j12\1.6.1\slf4j-log4j12-1.6.1.jar;D:\maven\.m2\repository\jline\jline\0.9.94\jline-0.9.94.jar;D:\maven\.m2\repository\junit\junit\3.8.1\junit-3.8.1.jar;D:\maven\.m2\repository\io\netty\netty\3.7.0.Final\netty-3.7.0.Final.jar;D:\maven\.m2\repository\log4j\log4j\1.2.15\log4j-1.2.15.jar;D:\maven\.m2\repository\javax\mail\mail\1.4\mail-1.4.jar;D:\maven\.m2\repository\javax\activation\activation\1.1\activation-1.1.jar;D:\maven\.m2\repository\javax\jms\jms\1.1\jms-1.1.jar;D:\maven\.m2\repository\com\sun\jdmk\jmxtools\1.2.1\jmxtools-1.2.1.jar;D:\maven\.m2\repository\com\sun\jmx\jmxri\1.2.1\jmxri-1.2.1.jar
2018-10-24 23:54:25,828 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.library.path=D:\wyonline\java\jdk1.7.0_25\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;D:/wyonline/java8/jre1.8.0_181/bin/server;D:/wyonline/java8/jre1.8.0_181/bin;D:/wyonline/java8/jre1.8.0_181/lib/amd64;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;D:\wyonline\java\jdk1.8.0_181\bin;D:\wyonline\java\jdk1.8.0_181\jre\bin;D:\wyonline\apache-maven-3.1.0\bin;D:\wyonline\newMysql\bin;C:\Program Files (x86)\Rational\common;D:\Program Files\TortoiseSVN\bin;D:\wyonline\eclipse;;.
2018-10-24 23:54:25,828 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.io.tmpdir=C:\Users\ADMINI~1.USE\AppData\Local\Temp\
2018-10-24 23:54:25,829 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:java.compiler=<NA>
2018-10-24 23:54:25,830 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:os.name=Windows 7
2018-10-24 23:54:25,834 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:os.arch=amd64
2018-10-24 23:54:25,835 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:os.version=6.1
2018-10-24 23:54:25,836 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:user.name=Administrator
2018-10-24 23:54:25,836 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:user.home=C:\Users\Administrator.USER-20150608SC
2018-10-24 23:54:25,837 main [zookeeper.ZooKeeper] 100 [INFO ] Client environment:user.dir=D:\wyonline\myworkspaces\framework\zkTest
2018-10-24 23:54:25,839 main [zookeeper.ZooKeeper] 438 [INFO ] Initiating client connection, connectString=192.168.74.4:2181,192.168.74.5:2181,192.168.74.6:2181 sessionTimeout=10000 watcher=com.wkp.test.zookeeper.watcher.cluster.DistributedConfig@37811015
2018-10-24 23:54:25,917 main [cluster.DistributedConfig] 36 [INFO ] 开始连接ZK服务器
2018-10-24 23:54:25,925 main-SendThread(192.168.74.5:2181) [zookeeper.ClientCnxn] 975 [INFO ] Opening socket connection to server 192.168.74.5/192.168.74.5:2181. Will not attempt to authenticate using SASL (unknown error)
2018-10-24 23:54:25,929 main-SendThread(192.168.74.5:2181) [zookeeper.ClientCnxn] 852 [INFO ] Socket connection established to 192.168.74.5/192.168.74.5:2181, initiating session
2018-10-24 23:54:25,951 main-SendThread(192.168.74.5:2181) [zookeeper.ClientCnxn] 1235 [INFO ] Session establishment complete on server 192.168.74.5/192.168.74.5:2181, sessionid = 0x166a6a1c8510008, negotiated timeout = 10000
switchNodeValue:DEFAULT
server2服务器*******************************
2018-10-24 23:54:25,971 main-EventThread [cluster.DistributedConfig] 65 [INFO ] zk 建立连接====================
2018-10-24 23:54:31,322 main-EventThread [cluster.DistributedConfig] 71 [INFO ] 节点创建================
switchNodeValue:ON
server2服务器*******************************
switchNodeValue:ON
server2服务器*******************************
2018-10-24 23:54:49,248 main-EventThread [cluster.DistributedConfig] 79 [INFO ] 节点数据更新==============
switchNodeValue:OFF
server2服务器*******************************
switchNodeValue:OFF
server2服务器*******************************
switchNodeValue:OFF
我们可以看到,当我们创建及更新"/switch"节点的时候,两个client都监听到了事件的发生,并且取到了最新的值,也就达到了分布式配置中心的作用了。
看到这里,您可以对zookeeper的使用场景有了一个更加清晰的认识,关于zookeeper的监听机制就介绍到这里,下一节将会给大家介绍一下zookeeper的ACL。