(5)zookeeper的watcher监听机制介绍

本文深入解析Zookeeper的Watcher机制,包括事件监听原理、事件类型、连接状态,以及通过代码示例展示如何使用Watcher。同时,介绍了Watcher在分布式配置中心的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本节介绍

最近比较忙又加上十一假期,有段时间没有写博客了,今天继续哈。。。。。。

本节会介绍一下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的方式有两种:

  1. 使用默认的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
  2. 给节点指定的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的方法与可监听事件的关系

注册方式NodeCreatedNodeChildrenChangedNodeDataChangedNodeDeleted
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。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值