zookeeper作為一個分散式服務框架,主要用來解決分散式資料一致性問題,對多種語言提供了API。這裡主要記錄下JAVA客戶端API的使用。
1.建立會話
客戶端可以通過建立一個ZooKeeper例項來連線zookeeper伺服器
ZooKeeper的4個建構函式如下:
- ZooKeeper(connectString, sessionTimeout, watcher);
- ZooKeeper(connectString, sessionTimeout, watcher,canBeReadOnly);
- ZooKeeper(connectString, sessionTimeout, watcher, sessionId, sessionPasswd);
- ZooKeeper(connectString, sessionTimeout, watcher, sessionId, sessionPasswd, canBeReadOnly);
引數說明:
connectString: 連線字串 例如 "127.0.0.1:2181"
sessionTimeout: 會話超時時間 以毫秒為單位的整型值 在sessionTimeout時間內服務端與客戶端沒有有效的心跳檢測 則會話失效
watcher: 預設的事件通知處理器
sessionId: 會話ID
sessionPasswd: 會話祕鑰
canBeReadOnly: 是否是隻讀
- public class ZookeeperSampleTest implements Watcher {
- private static CountDownLatch connectedSemaphore = new CountDownLatch(1);
- public static void main(String args[]) throws IOException, InterruptedException{
- ZooKeeper zk = new ZooKeeper("192.168.1.138:2181",5000,new ZookeeperSampleTest());
- System.out.println(zk.getState());
- try {
- connectedSemaphore.await();
- } catch (Exception e) {
- // TODO: handle exception
- }
- Long sessionId = zk.getSessionId();
- byte[] password = zk.getSessionPasswd();
- zk = new ZooKeeper("192.168.1.138:2181",5000,new ZookeeperSampleTest(),1L,"test".getBytes());
- zk = new ZooKeeper("192.168.1.138:2181",5000,new ZookeeperSampleTest(),sessionId,password);
- Thread.sleep(Integer.MAX_VALUE);
- //System.out.println("ZooKeeper session established");
- }
- @Override
- public void process(WatchedEvent event) {
- // TODO Auto-generated method stub
- System.out.println("Receive watched event :" + event);
- if(event.getState()==KeeperState.SyncConnected){
- connectedSemaphore.countDown();
- }
- }
- }
2.建立節點
建立節點的方式分為同步和非同步,建構函式如下:
- zk.create(path, data, acl, createMode);
- , data, acl, createMode, cb, ctx);
引數說明:
path: 建立節點的路徑 如:/zk-test
data[]: 位元組陣列,節點資料
acl: 許可權
createMode: 節點型別 分為4種: 永續性節點,永續性有序節點,臨時節點,臨時有序節點
cb: 回撥函式 需要實現StringCallback介面
ctx: 上下文 一般用於回撥函式時候使用
- public class ZookeeperSampleCreateTest implements Watcher {
- public static CountDownLatch connectedSemaphore = new CountDownLatch(1);
- public static void main(String[] args) throws IOException, InterruptedException, KeeperException{
- ZooKeeper zk = new ZooKeeper("192.168.1.138:2181",5000,new ZookeeperSampleCreateTest());
- connectedSemaphore.await();
- /*同步的方式*/
- /*String path1 = zk.create("/zk-test-ephemeral-", "test-ephemeral".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
- System.out.println("Success create node :" + path1);
- String path2 = zk.create("/zk-test-ephemeral-", "test-ephemeral-sequential".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
- System.out.println("Success create node :" + path2);*/
- /*非同步的方式*/
- zk.create("/zk-test-ephemeral-", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL,new IStringCallback(),"i am context");
- zk.create("/zk-test-ephemeral-", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL,new IStringCallback(),"i am context");
- zk.create("/zk-test-ephemeral-", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL,new IStringCallback(),"i am context");
- Thread.sleep(Integer.MAX_VALUE);
- }
- @Override
- public void process(WatchedEvent event) {
- // TODO Auto-generated method stub
- if(KeeperState.SyncConnected == event.getState()){
- connectedSemaphore.countDown();
- }
- }
- }
- class IStringCallback implements AsyncCallback.StringCallback{
- @Override
- public void processResult(int rc, String path, Object ctx, String name) {
- // TODO Auto-generated method stub
- System.out.println("Create path result: [" + rc + "," + path + "," + ctx + ", real path name " + name);
- }
- }
3.刪除節點
- zk.delete(path,version);
- zk.delete(path,version,cb,ctx);
引數說明:
path:節點路徑
version:版本號
cb: 回撥函式
ctx: 上下文
4.獲取子節點
getChildren有8個過載方法
- zk.getChildren(path, watch);
- zk.getChildren(path, watcher);
- zk.getChildren(path, watch, stat);
- zk.getChildren(path, watcher, stat);
- zk.getChildren(path, watch, cb, ctx);
- zk.getChildren(path, watcher, cb, ctx);
其中 回撥函式有兩種 ChildrenCallback Children2Callback
引數說明:
path:節點路徑
watch: boolean型別 如果為true 表示使用預設的Watcher 為false表示不需要Watcher
watcher: 通知處理器 在本次獲取子節點以後 一旦子節點有變化機會收到服務端傳來的通知
stat: 指定資料節點的節點狀態資訊,傳入一箇舊的stat物件,當執行方法後 stat會被伺服器響應的新stat替換
cb:回撥函式 有兩種型別 上面已經說過
ctx: 上下文
5.獲取節點資料
獲取節點資料有4個過載方法
- zk.getData(path, watch, stat);
- zk.getData(path, watcher, stat);
- zk.getData(path, watch, cb, ctx);
- zk.getData(path, watcher, cb, ctx);
引數說明:
path: 節點路徑
watch: boolean型別 如果為true 表示使用預設的Watcher 為false表示不需要Watcher
stat: 指定資料節點的節點狀態資訊,傳入一箇舊的stat物件,當執行方法後 stat會被伺服器響應的新stat替換
cb:回撥函式 有兩種型別 上面已經說過
ctx: 上下文
在獲取節點資料時候 如果註冊watcher 在節點資料傳送變化的時候會通知客戶端,當客戶端收到通知以後,如果想下次資料傳送變化再次收到通知,
需要重新註冊watcher,獲取子節點機制也如此
6.更新節點資料
更新節點資料也分為同步非同步兩個方法
- zk.setData(path, data, version);
- zk.setData(path, data, version, cb, ctx);
引數說明:同上
- public class ZookeeperSampleGetDataTest implements Watcher {
- public static CountDownLatch connectedSemaphore = new CountDownLatch(1);
- public static Stat stat = new Stat();
- public static ZooKeeper zk = null;
- public static void main(String[] args) throws IOException, KeeperException, InterruptedException{
- String path = "/zk-test";
- zk = new ZooKeeper("192.168.1.138:2181", 5000, new ZookeeperSampleGetDataTest());
- connectedSemaphore.await();
- //獲取子節點
- /*zk.delete(path, 0);
- zk.create(path, "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
- zk.create(path+"/c1", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
- //同步方法獲取children
- //List<String> childs = zk.getChildren(path, true);
- //System.out.println(childs);
- //非同步方法獲取children
- zk.getChildren(path, true, new IChildren2Callback(), null);
- zk.create(path+"/c2", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
- Thread.sleep(Integer.MAX_VALUE);*/
- //獲取節點資料
- zk.delete(path, 0);
- zk.create(path, "123".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
- System.out.println(new String(zk.getData(path, true, stat)));
- /** czxid: 建立該節點的事務ID mzxid: 更新該節點的事務ID version: 資料版本*/
- System.out.println("Czxid: " + stat.getCzxid() + "Mzxid: " + stat.getMzxid() + "Version: " + stat.getVersion());
- zk.setData(path, "123".getBytes(), -1);
- Thread.sleep(Integer.MAX_VALUE);
- }
- @Override
- public void process(WatchedEvent event) {
- // TODO Auto-generated method stub
- if(KeeperState.SyncConnected==event.getState()){
- if(EventType.None==event.getType() && null==event.getPath()){
- connectedSemaphore.countDown();
- }else if(event.getType()==EventType.NodeChildrenChanged){
- try {
- System.out.println("Get Child :" + zk.getChildren(event.getPath(), true));
- } catch (KeeperException | InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }else if(event.getType()==EventType.NodeDataChanged){
- try {
- System.out.println(new String(zk.getData(event.getPath(), true, stat)));
- System.out.println("Czxid: " + stat.getCzxid() + "Mzxid: " + stat.getMzxid() + "Version: " + stat.getVersion());
- } catch (KeeperException | InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
- }
- class IChildren2Callback implements AsyncCallback.Children2Callback{
- @Override
- public void processResult(int rc, String path, Object ctx,
- List<String> childrens, Stat stat) {
- // TODO Auto-generated method stub
- System.out.println("Get Children znode result: [response code: " + rc + ", param path: " + path + ", ctx " + ctx
- + ", childrens :" + childrens + ", stat: " + stat);
- }
- }
其中更新節點資料 版本version問題 -1表示基於資料的最新版本更新 這裡可以作為分散式鎖的一個思路 如果客戶端參入的version不是資料最新版本則會更新失敗
比如目前節點"/zk-test"的資料版本為 2 而某個客戶端嘗試 執行 setData("/zk-test","test".getBytes(),1) 由於傳入version為1 < 伺服器目前版本2 這樣就會更新失敗
7.檢測節點是否存在
- zk.exists(path, watch);
- zk.exists(path, watcher);
- zk.exists(path, watch, cb, ctx);
- zk.exists(path, watcher, cb, ctx);
如果判斷節點是否存在是 註冊watcher 會對節點是否存在進行監聽--建立節點,刪除節點,節點資料更新都會通知客戶端
8.許可權控制
zookeeper提供了ACL的許可權控制機制,簡單來說就是通過控制zookeeper伺服器上資料節點的ACL,來控制客戶端對節點的訪問許可權
- addAuthInfo(String scheme,byte[] auth);
引數說明:
scheme: 許可權控制模式 分為: world ,auth,digest,ip和super
auth: 具體的許可權資訊 類似於shiro的許可權字串
如下程式碼:
- <span style="white-space:pre;"> </span>ZooKeeper zk1 = new ZooKeeper("192.168.1.138:2181",5000,new ZookeeperSampleCreateTest());
- zk1.addAuthInfo("digest", "test:true".getBytes());
- zk1.create("/zk-test-auth", "123".getBytes(), Ids.CREATOR_ALL_ACL, CreateMode.EPHEMERAL);
- ZooKeeper zk2 = new ZooKeeper("192.168.1.138:2181",5000,new ZookeeperSampleCreateTest());
- zk2.addAuthInfo("digest", "test:true".getBytes());
- System.out.println(new String(zk2.getData("/zk-test-auth", false, null)));
- ZooKeeper zk3 = new ZooKeeper("192.168.1.138:2181",5000,new ZookeeperSampleCreateTest());
- zk3.addAuthInfo("digest", "test:false".getBytes());
- zk3.getData("/zk-test-auth", false, null);
zk2設定了正確的許可權 所以可以獲取到節點資料 zk3則會拋異常
org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /zk-test-auth