1. 程式人生 > >Zookeeper的監聽機制api與原理

Zookeeper的監聽機制api與原理

1.連線Zookeeper,註冊監聽

ZooKeeper zkCli = new ZooKeeper("192.168.50.183:2181,192.168.50.184:2181,192.168.50.185:2181", 3000, new Watcher() {
				//監聽回撥
				@Override
				public void process(WatchedEvent event) {
					System.out.println("正在監聽中.....");
				}
			});

2.註冊監聽getChilren

通過zkCli.getchildren("/",new watch()){}來註冊監聽,監聽的是整個根節點,但是這個監聽只能監聽一次。
執行緒休眠是為了讓監聽等待事件發生,不然會隨著程式直接執行完。

public class WatchDemo1 {
	
	static List<String> children = null;
	public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
		

		ZooKeeper zkCli = new ZooKeeper("192.168.50.183:2181,192.168.50.184:2181,192.168.50.185:2181", 3000, new Watcher() {
				
				//監聽回撥
				@Override
				public void process(WatchedEvent event) {
					System.out.println("正在監聽中.....");
				}
			});
		
			//監聽目錄
			children = zkCli.getChildren("/", new Watcher() {
			
			@Override
			public void process(WatchedEvent event) {
				
				System.out.println("監聽路徑為:" + event.getPath());
				System.out.println("監聽的型別為:" + event.getType());
				System.out.println("資料被2貨修改了!!!");
				
				for(String c:children) {
					System.out.println(c);
				}
			}
		});
			
			Thread.sleep(Long.MAX_VALUE);
		
	}
	
		
}

可以通過修改zk客戶端的/節點下的子節點,getchilren會返回列表(/下的子節點資訊)

3.註冊監聽getData

getData監聽的為一個節點
同樣只監聽一次,返回的是該節點的內容

public class WatchDemo {
	public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
		ZooKeeper zkCli = new ZooKeeper("192.168.50.183:2181,192.168.50.184:2181,192.168.50.185:2181", 3000, new Watcher() {
			
			//監聽回撥
			@Override
			public void process(WatchedEvent event) {
				
			}
		});
		
		byte[] data = zkCli.getData("/hunter", new Watcher() {
			//監聽的具體內容
			@Override
			public void process(WatchedEvent event) {
				System.out.println("監聽路徑為:" + event.getPath());
				System.out.println("監聽的型別為:" + event.getType());
				System.out.println("資料被2貨修改了!!!");
			}
		}, null);
		
		System.out.println(new String(data));
		
		Thread.sleep(Long.MAX_VALUE);
	}
}

4.永久監聽

public class ZkClient {
	public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
		//1.獲取連線
		ZkClient zkClient = new ZkClient();
		zkClient.getConnect();
		
		//2.監聽服務的節點資訊
		zkClient.getServers();;
		
		//3.業務邏輯(一直監聽)
		zkClient.getWatch();
	}
	
	//3.業務邏輯
	public void getWatch() throws InterruptedException {
		Thread.sleep(Long.MAX_VALUE);
	}
	
	//2.監聽服務的節點資訊
	public void getServers() throws KeeperException, InterruptedException {
		List<String> children = zkCli.getChildren("/servers", true);
		ArrayList<String> serverList = new ArrayList<String>();
		
		//獲取每個節點的資料
		for(String c:children) {
			byte[] data = zkCli.getData("/servers/" + c, true, null);
			serverList.add(new String(data));
		}
		
		//列印伺服器列表
		System.out.println(serverList);
		
	}
	
	private String connectString = "192.168.232.132:2181,192.168.232.133:2181,192.168.232.134:2181";
	private int sessionTimeout = 3000;
	ZooKeeper zkCli;
	
	//1.連線叢集
	public void getConnect() throws IOException {
		zkCli = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
			
			@Override
			public void process(WatchedEvent event) {
				List<String> children;	
				try {
					//監聽父節點
					children = zkCli.getChildren("/servers", true);
					
					//建立集合儲存伺服器列表
					ArrayList<String> serverList = new ArrayList<String>();
					
					//獲取每個節點的資料
					for(String c:children) {
						byte[] data = zkCli.getData("/servers/" + c, true, null);
						serverList.add(new String(data));
					}
					
					//列印伺服器列表
					System.out.println(serverList);
					
				} catch (KeeperException e) {
					
					e.printStackTrace();
				} catch (InterruptedException e) {
					
					e.printStackTrace();
				}
			}
		});
	}
	
}

服務端上下線機器,客戶端都能動態感知,這裡是先通過getchilren獲得根節點下的子節點資訊列表,然後通過getData來獲得每個子節點的內容,並傳給ArrayList,最後通過輸出ArrayList來獲得當前線上的機器

5.總結

1.從1-3的程式碼可以看出,zookeeper註冊的監聽是一次的,如果你還需要監聽第二次,那麼就要重新註冊。
那我們永久監聽是怎麼做到的呢?
2.可以看到在我們連線zookeeper的時候,註冊了監聽,然後在process方法中,我們的getChildren,getData的第二個引數為true,這裡是使用預設的監聽,我的理解是會回撥到我們連線zookeeper的時候註冊監聽的process方法,那因為我們的getChildren,getData是放在這個方法裡的,每次發生一個事件,然後就一直重複這樣的行為,達到永久監聽的效果。
3.這裡我們可以測試下,getChildren,getData不放在process當中,並且引數為true,那我的測試結果為,監聽了一次,監聽完了後,又返回連線zk時的process方法中的語句.這裡就證明了我的理解應該是對了。