构建项目
zookeeper官方的客户端没有和服务端代码分离,它们都是同一个jar文件,所以我们直接引入zookeeper的maven即可,这里的版本请保持与服务端一致,可能会有许多兼容问题
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.8</version>
</dependency>
创建客户端实例
package com.zookeeper;
import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
/**
* @author :guosong
* @date :2023/4/20 9:34 AM
* @version: V1.0
* @description:
**/
@Slf4j
public class ZookeeperClient {
private static final String ZK_ADDRESS = "localhost:2181";
private static final int SESSION_TIMEOUT = 5000;
private static ZooKeeper zooKeeper;
private static final String ZK_NODE = "/zk_node";
public static void main(String[] args) throws IOException, InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
new ZooKeeper(ZK_ADDRESS,SESSION_TIMEOUT, event -> {
if (event.getState() == Watcher.Event.KeeperState.SyncConnected && event.getType() == Watcher.Event.EventType.None) {
countDownLatch.countDown();
log.info("连接成功");
}
});
log.info("连接中");
countDownLatch.await();
}
}
创建zookeeper实例
public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly)
connectString: Zookeeper 服务器列表,由英文逗号分隔开host:port字符串组成,每一个都代表一 台Zookeeper机器,如host1:port1,host2:port2,host3:port3。另外,也可以在connectString中设置客户端连接上Zookeeper后的根目录,方法是在host:port字符串之后添加上这个根目录,例如,host1:port,host2:port2,host3:port3/zk-node,这样就指定了该客户端连接上Zookeeper服务器之后,所有对Zookeeper的操作,都会基于这个根目录。例如,客户端对/sub-node 的操作,最终创建/zk-node/sub-node,这个目录也叫Chroot,即客户端隔离命名空间。
sessionTimeout:会话超时时间,是以一个"毫秒"为单位的整型值。在zookeeper中有会话的概念,在一个会话周期内,zookeeper客户端和服务器之间会通过心跳检测机制来维持会话的有效性,一旦在sessionTimeout 时间内没有进行有效的心跳检测,会话会失效。
watcher: zooKeeper允许客户端在构造方法中传入一个接口watcher(org.apache.zookeeper.Watcher)的实现类对象来作为默认的Watcher事件通知处理器。当然,该参数可以设置为null以表明不需要设置默认的Watcher处理器。
canBeReadOnly:这是一个boolean类型的参数,用于标识当前会话是否支持"read-only(只读)“模式。默认情况下,在zookeeper集群中,一个机器如果和集群中过半及以上机器失去了网络连接,那么这个节气将不再处理客户端请求(包括读写请求)。但是在某些情景下,当Zookeeper服务发生此类故障的时候,我们还是希望Zookeeper的 "read-only"模式
sessionId 和sessionPasswd: 分别代表会话ID 和 会话密钥。这两个参数能够唯一确定一个会话,同时客户端使用这两个参数可以实现客户端会话复用,从而达到恢复会话的效果。具体使用方法是,第一次连接上Zookeeper服务器时,通过调用Zookeeper对象实例的一下两个接口,即可获得当前会话的ID和密钥:long getSessionId(); byte[] getSessionPasswd(); 获取到这两个参数值之后,就可以在下次创建Zookeeper对象实例的时候传入构造方法
/**
* 创建同步节点
*/
public static void syn() throws IOException, InterruptedException, KeeperException {
ZooKeeper zooKeeper = initZookeeper();
String path = zooKeeper.create("/client-node", "data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
log.info("create path: {}",path);
}
/**
* 创建异步节点
*/
public static void async() throws InterruptedException, IOException {
ZooKeeper zooKeeper = initZookeeper();
zooKeeper.create("/async_node","data".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT,(rc,path,ctx,name) -> log.info("rc {}, path {}, ctx{}, name{}",rc,path,ctx,name),"context");
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
}
/**
* 修改节点
*/
public static void setTest() throws KeeperException, InterruptedException, IOException {
Stat stat = new Stat();
ZooKeeper zooKeeper = initZookeeper();
byte[] data = zooKeeper.getData("/async_node", false, stat);
log.info("修改之前:{}",new String(data));
zooKeeper.setData("/async_node","changedaaa".getBytes(),stat.getVersion());
byte[] dataAfter = zooKeeper.getData("/async_node", false, stat);
log.info("修改后:{}",new String(dataAfter));
}