1.Zookeeper Watcher(監(jiān)聽機制)
Zookeeper 提供了分布式 數(shù)據(jù)發(fā)布和訂閱功能,一個典型的發(fā)布和訂閱模型系統(tǒng)定義了一種一對多的訂閱關系,能讓多個訂閱者同時監(jiān)聽某一個主題的對象,當這個主題對象自身狀態(tài)變化時,會通知所有訂閱者,使它們能夠做出相應的處理。
Zookeeper中引入了Watcher機制來實現(xiàn)這種分布式通知的功能。Zookeeper允許客戶端向服務端注冊一個Watcher監(jiān)聽。當服務端的一些事件出發(fā)了Watcher監(jiān)聽機制,就會向指定得客戶端發(fā)送一個事件通知來實現(xiàn)分布式的通知功能。
觸發(fā)事件種類: 節(jié)點創(chuàng)建、節(jié)點刪除、節(jié)點改變、子節(jié)點改變等。
總的來說可以概括Watcher分為以下三個過程: 客戶端向服務端注冊Watcher、服務端事件觸發(fā)Watcher、客戶端回調(diào)Watcher得到觸發(fā)事件情況。????
2.Watch機制特點
一次性觸發(fā)
事件觸發(fā)監(jiān)聽,一個Watcher Event 就會被發(fā)送到設置監(jiān)聽的客戶端,這種效果是一次性的,后續(xù)再發(fā)生同樣的事件,不會觸發(fā)機制。
事件封裝
Zookeeper使用WatchedEvent對象來封裝服務端事件并傳遞。
WatchedEvent包含每一個事件的三個基本屬性:
通知狀態(tài)(keeperState) 、事件類型(EventType)、節(jié)點路徑(path)
Event 異步發(fā)送
Watcher的通知事件是從服務端異步發(fā)送到客戶端的。
先注冊再觸發(fā)
Zookeeper的Watch機制,必須客戶端在服務端注冊監(jiān)聽,服務器端觸發(fā)監(jiān)聽機制,才會通知客戶端。
3.通知狀態(tài)和事件類型
同一個事件類型在不同的通知狀態(tài)中代表的含義有所不同,下表列舉了常見的通知狀態(tài)和事件類型。
事件封裝:Watcher得到的事件是被封裝過的, 包括三個內(nèi)容keeperState, eventType, path
其中連接狀態(tài)事件(type=None, path=null)不需要客戶端注冊,客戶端只要有需要直接處理就行了。
4.Shell 客戶端設置Watcher
設置節(jié)點數(shù)據(jù)變動監(jiān)聽:
通過另一個客戶端更改節(jié)點數(shù)據(jù):
此時設置監(jiān)聽的節(jié)點收到通知:
5.ZooKeeperJava?API操作
這里操作Zookeeper的JavaAPI使用的是一套zookeeper客戶端框架 Curator ,解決了很多Zookeeper客戶端非常底層的細節(jié)開發(fā)工作 。
Curator包含了幾個包:
curator-framework:對zookeeper的底層api的一些封裝
curator-recipes:封裝了一些高級特性,如:Cache事件監(jiān)聽、選舉、分布式鎖、分布式計數(shù)器等
Maven依賴(使用curator的版本:2.12.0,對應Zookeeper的版本為:3.4.x,如果跨版本會有兼容性問題,很有可能導致節(jié)點操作失敗):
? ? 1.引入maven坐標
<dependencies>
????????<dependency>
????????????<groupId>org.apache.curator</groupId>
????????????<artifactId>curator-framework</artifactId>
????????????<version>2.12.0</version>
????????</dependency>
????????<dependency>
????????????<groupId>org.apache.curator</groupId>
????????????<artifactId>curator-recipes</artifactId>
????????????<version>2.12.0</version>
????????</dependency>
????????<dependency>
????????????<groupId>com.google.collections</groupId>
????????????<artifactId>google-collections</artifactId>
????????????<version>1.0</version>
????????</dependency>
????????<dependency>
????????????<groupId>junit</groupId>
????????????<artifactId>junit</artifactId>
????????????<version>RELEASE</version>
????????</dependency>
????????<dependency>
????????????<groupId>org.slf4j</groupId>
????????????<artifactId>slf4j-simple</artifactId>
????????????<version>1.7.25</version>
????????</dependency>
????</dependencies>
????<build>
????????<plugins>
????????????<!--java編譯插件 -->
????????????<plugin>
????????????????<groupId>org.apache.maven.plugins</groupId>
????????????????<artifactId>maven-compiler-plugin</artifactId>
????????????????<version>3.2</version>
????????????????<configuration>
????????????????????<source>1.8</source>
????????????????????<target>1.8</target>
????????????????????<encoding>UTF-8</encoding>
????????????????</configuration>
????????????</plugin>
????????</plugins>
???</build>
2.節(jié)點的操作
/*
?創(chuàng)建節(jié)點
?*/
@Test
public?void?createZnode()?throws?Exception {
//1:定制一個重試策略
/*
param1: 重試的間隔時間
param2:重試的最大次數(shù)
?*/
RetryPolicy retryPolicy =?new?ExponentialBackoffRetry(1000,1);
//2:獲取一個客戶端對象
/*
???param1:要連接的Zookeeper服務器列表
???param2:會話的超時時間
???param3:鏈接超時時間
???param4:重試策略
?*/
String connectionStr =?"192.168.88.161:2181,192.168.88.162:2181,192.168.88.163:2181";
CuratorFramework client =?CuratorFrameworkFactory.newClient(connectionStr,?8000,?8000,?retryPolicy);
//3:開啟客戶端
client.start();
//4:創(chuàng)建節(jié)點
/*
??節(jié)點類型:
???CreateMode.PERSISTENT:永久節(jié)點
???CreateMode.PERSISTENT_SEQUENTIAL:永久序列化節(jié)點
???CreateMode.EPHEMERAL:臨時節(jié)點
???CreateMode.EPHEMERAL_SEQUENTIAL:臨時序列化節(jié)點
???/hello2 :節(jié)點路徑
???world :節(jié)點數(shù)據(jù)
?*/
client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/hello2","world".getBytes());
//5:關閉客戶端
client.close();
}