引入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接口方法。可以参考异步创建节点的类实现。