Zookeeper学习之路——JAVA API操作Zookeeper

引入maven依赖

<dependencies>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.12</version>
        </dependency>
</dependencies>

连接zookeeper

在zookeeper提供的jar包实现中,存在着以下几个构造方法:

public ZooKeeper(String connectString, int sessionTimeout, 
Watcher watcher)
public ZooKeeper(String connectString, int sessionTimeout, 
Watcher watcher,boolean canBeReadOnly)
public ZooKeeper(String connectString, int sessionTimeout, 
Watcher watcher,long sessionId, byte[] sessionPasswd)
public ZooKeeper(String connectString, int sessionTimeout,
 Watcher watcher,long sessionId, byte[] sessionPasswd, 
 boolean canBeReadOnly)

几个构造方法中存在着connectString,sessionTimeout,watcher,sessionId,sessionPasswd,canBeReadOnly这几个参数,具体参数的含义如下

  • connectString:是指我们需要连接的zookeeper的服务器的ip地址和端口号,例如我的是”192.168.28.124:2181”,也可以为这个字符串加上ZNode,这样下面的操作都是基于该节点的。
  • sessionTimeout:这个是回话超时时间,以毫秒为单位。客户端和服务器之间通过心跳来维持之间的回话,如果在回话期间没有进行心跳检查,说明该回话已经结束。
  • watcher:该接口类作为事件通知处理器,因为客户端到服务器的连接是异步的,所以在服务器给客户端响应的时候,应该有个通知器,告诉客户端连接成功的信息。
  • canBeReadOnly:在集群中可能会发生脑裂的情况,在这样的情况在该机器就不能对外提供服务,但是在一些情况我们需要该机器依然对外提供服务,当然此时已经不能提供写的服务,但是可以提供读的服务。这个时候我们需要将该参数设置成true
  • sessionId,sessionPasswd:这两个参数可以确定唯一一个回话,这样我们就可以达到会话复用的目的。

代码演示

package zookeeper;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.KeeperState;

public class ZooKeeperBasicConnection {

    private static CountDownLatch semaphore = new CountDownLatch(1);

    public static void main(String[] args) {
        try {
            ZooKeeper zooKeeper = new ZooKeeper("192.168.28.124:2181", 5000, new Watcher() {

                /**
                 * 通过匿名类来实现对服务器信息响应的回调
                 */
                @Override
                public void process(WatchedEvent event) {
                    // TODO Auto-generated method stub
                    System.out.println("receive watch event" + event);
                    if(KeeperState.SyncConnected == event.getState()) {
                        semaphore.countDown();
                    }
                }});
            System.out.println(zooKeeper.getState());
            //只要服务器一直没有响应,程序就一直阻塞在此处
            semaphore.await();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        System.out.println("zookeeper session established");
    }
}

创建ZNode

提供的方法如下:

public String create(final String path, byte data[], List<ACL> acl,
            CreateMode createMode)
public void create(final String path, byte data[], List<ACL> acl,
            CreateMode createMode,  StringCallback cb, Object ctx)

jar包中提供了两种实现的方式:同步和异步。

  • path:节点名称
  • data[]:节点数据
  • acl:权限控制方式
  • createMode:节点类型CreateMode.EPHEMERAL_SEQUENTIAL(临时顺序节点),CreateMode.EPHEMERAL(临时节点),CreateMode.PERSISTENT(持久化节点),CreateMode.PERSISTENT_SEQUENTIAL(持久化顺序节点)。

同步创建节点代码

package zookeeper;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;

public class SyncCreateZNode {

private static CountDownLatch semaphore = new CountDownLatch(1);

    public static void main(String[] args) {
        try {
            ZooKeeper zooKeeper = new ZooKeeper("192.168.28.124:2181", 5000, new Watcher() {

                /**
                 * 通过匿名类来实现对服务器信息响应的回调
                 */
                @Override
                public void process(WatchedEvent event) {
                    // TODO Auto-generated method stub
                    System.out.println("receive watch event" + event);
                    if(KeeperState.SyncConnected == event.getState()) {
                        semaphore.countDown();
                    }
                }});
            System.out.println(zooKeeper.getState());
            //只要服务器一直没有响应,程序就一直阻塞在此处
            semaphore.await();
            String firstNode = zooKeeper.create("/first_node", "123456".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            System.out.println("create node : " + firstNode);
            String secondNode = zooKeeper.create("/second_node", "123456".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            System.out.println("create node : " + secondNode);
            String thirdNode = zooKeeper.create("/third_node", "123456".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println("create node : " + thirdNode);
            String forthNode = zooKeeper.create("/forth_node", "123456".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
            System.out.println("create node : " + forthNode);
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        System.out.println("zookeeper session established");
    }
}

查看服务器节点是否创建

[zk: localhost:2181(CONNECTED) 0] ls /
[third_node, zookeeper, forth_node0000000006, sequenceNode0000000002]

看到服务器上只有我们创建的第三个和第四个节点,那是因为第一个和第二个都是临时节点,临时节点只存在当前的会话中,服务器上的是另一个会话,所以我们在这个回话中是看不到另一个会话中的节点的。

异步创建节点代码

package zookeeper;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.AsyncCallback.StringCallback;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;

public class AsyncCreateZNode {

private static CountDownLatch semaphore = new CountDownLatch(1);

    public static void main(String[] args) {
        try {
            ZooKeeper zooKeeper = new ZooKeeper("192.168.28.124:2181", 5000, new Watcher() {

                /**
                 * 通过匿名类来实现对服务器信息响应的回调
                 */
                @Override
                public void process(WatchedEvent event) {
                    // TODO Auto-generated method stub
                    System.out.println("receive watch event" + event);
                    if(KeeperState.SyncConnected == event.getState()) {
                        semaphore.countDown();
                    }
                }});
            System.out.println(zooKeeper.getState());
            //只要服务器一直没有响应,程序就一直阻塞在此处
            semaphore.await();
            /**
             * 使用异步创建节点方法没有返回值
             */
            zooKeeper.create("/afirst_node", "123456".getBytes(), Ids.OPEN_ACL_UNSAFE, 
                    CreateMode.EPHEMERAL_SEQUENTIAL,new ZCallBack(),"context");

            zooKeeper.create("/asecond_node", "123456".getBytes(), Ids.OPEN_ACL_UNSAFE, 
                    CreateMode.EPHEMERAL,new ZCallBack(),"context");

            zooKeeper.create("/athird_node", "123456".getBytes(), Ids.OPEN_ACL_UNSAFE, 
                    CreateMode.PERSISTENT,new ZCallBack(),"context");

            zooKeeper.create("/aforth_node", "123456".getBytes(), Ids.OPEN_ACL_UNSAFE, 
                    CreateMode.PERSISTENT_SEQUENTIAL,new ZCallBack(),"context");
            Thread.sleep(Integer.MAX_VALUE);
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        System.out.println("zookeeper session established");
    }
}
/**
 * 异步回调类需要实现AsyncCallback,StringCallback两个接口,并且重写processResult方法。
 * @author Jiang
 *
 */
class ZCallBack implements AsyncCallback,StringCallback{

    @Override
    //rc返回值0:返回成功 -4:客户端和服务端连接断开 -110:指点节点已经存在 -112:会话过期
    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 is" + name);
    }

}

删除ZNode

提供两个接口方法:

public void delete(final String path, int version)
public void delete(final String path, int version,
 VoidCallback cb,Object ctx)

该方法同样是提供了同步和异步的方法,参数的含义和创建节点方法中的含义相同。

同步删除节点

package zookeeper;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.KeeperState;

public class SyncDeleteZNode {

private static CountDownLatch semaphore = new CountDownLatch(1);

    public static void main(String[] args) {
        try {
            ZooKeeper zooKeeper = new ZooKeeper("192.168.28.124:2181", 5000, new Watcher() {

                /**
                 * 通过匿名类来实现对服务器信息响应的回调
                 */
                @Override
                public void process(WatchedEvent event) {
                    // TODO Auto-generated method stub
                    System.out.println("receive watch event" + event);
                    if(KeeperState.SyncConnected == event.getState()) {
                        semaphore.countDown();
                    }
                }});
            System.out.println(zooKeeper.getState());
            //只要服务器一直没有响应,程序就一直阻塞在此处
            semaphore.await();
            zooKeeper.delete("/third_node", 0);
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

查看节点信息,接口中操作的third_node节点已被删除

[zk: localhost:2181(CONNECTED) 0] ls /
[third_node, zookeeper, sequenceNode0000000002, athird_node, forth_node0000000006, aforth_node0000000011]
[zk: localhost:2181(CONNECTED) 1] ls /third_node
[]
[zk: localhost:2181(CONNECTED) 2] ls /   
[zookeeper, sequenceNode0000000002, athird_node, forth_node0000000006, aforth_node0000000011]

异步的方式,所要提供的参数跟创建节点异步方式相同,需要一个实现AsyncCallback,StringCallback接口的回调类,同时重写process方法。

获取ZNode

获取节点在jar中提供了以下几个方法

public List<String> getChildren(final String path, Watcher watcher)
public List<String> getChildren(String path, boolean watch)
public void getChildren(final String path, Watcher watcher,
ChildrenCallback cb, Object ctx)
public void getChildren(String path, boolean watch, ChildrenCallback cb,Object ctx)
public List<String> getChildren(final String path, Watcher watcher,
Stat stat)
public List<String> getChildren(String path, boolean watch, Stat stat)
public void getChildren(final String path, Watcher watcher,
Children2Callback cb, Object ctx)
public void getChildren(String path, boolean watch, Children2Callback cb,Object ctx)
  • watcher:该参数表示在一次获取节点之后,如果该节点列表发生变更,该类需要向客户端发送通知。
  • watch:如果设置true表示客户端会使用上下文中默认的watcher,设置为false表示不需要watcher。
  • stat:指定数据节点的节点状态信息。
package zookeeper;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;

public class SyncGetZNode implements Watcher{

    static ZooKeeper zooKeeper = null;
    private static CountDownLatch semaphore = new CountDownLatch(1);

    public static void main(String[] args) {
        try {
            zooKeeper = new ZooKeeper("192.168.28.124:2181", 5000, new SyncGetZNode());
            System.out.println(zooKeeper.getState());
            //只要服务器一直没有响应,程序就一直阻塞在此处
            semaphore.await();
            String jiang = zooKeeper.create("/jiang", "123456".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println("create node : " + jiang);
            String conjane = zooKeeper.create("/jiang/conjane", "123456".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println("create node : " + conjane);
            java.util.List<String> nodes = zooKeeper.getChildren("/jiang", true);
            System.out.println(nodes);
            String conjane2 = zooKeeper.create("/jiang/conjane2", "123456".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println("create node : " + conjane2);
            Thread.sleep(Integer.MAX_VALUE);
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

    @Override
    public void process(WatchedEvent event) {
        // TODO Auto-generated method stub
        System.out.println("receive watch event" + event);
        if(KeeperState.SyncConnected == event.getState() && null == event.getPath()) {
            semaphore.countDown();
        }else if(event.getType() == EventType.NodeChildrenChanged) {
            try {
                System.out.println("get children again, and the changed is : " + zooKeeper.getChildren(event.getPath(), true));
            } catch (KeeperException | InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

执行结果如下:

CONNECTING
receive watch eventWatchedEvent state:SyncConnected type:None path:null
create node : /jiang
create node : /jiang/conjane
[conjane]
receive watch eventWatchedEvent state:SyncConnected type:NodeChildrenChanged path:/jiang
create node : /jiang/conjane2
get children again, and the changed is : [conjane, conjane2]

异步获取ZNode

同步和异步的区别在于异步需要一个回调类,这个类需要实现AsyncCallback接口和Children2Callback接口方法。可以参考异步创建节点的类实现。

猜你喜欢

转载自blog.csdn.net/u010871004/article/details/80711870