package com.test.zk;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class BaseZookeeper implements Watcher {
public ZooKeeper zooKeeper;
private static final int SESSION_TIME_OUT = 6000;
private CountDownLatch countDownLatch = new CountDownLatch(1);
/**
* 连接zookeeper
*
* @param host
* @throws IOException
* @throws InterruptedException
*/
public void connectZookeeper(String host) throws IOException, InterruptedException {
zooKeeper = new ZooKeeper(host, SESSION_TIME_OUT, this);
countDownLatch.await();
System.out.println("zookeeper connect ok");
}
/**
* 实现watcher的接口方法,当连接zookeeper成功后,zookeeper会通过此方法通知watcher
* 此处为如果接受到连接成功的event,则countDown,让当前线程继续其他事情。
*/
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.SyncConnected) {
System.out.println("watcher received event");
countDownLatch.countDown();
}
}
/**
* 根据路径创建节点,并且设置节点数据
*
* @param path
* @param data
* @return
* @throws KeeperException
* @throws InterruptedException
*/
public String createNode(String path, byte[] data) throws KeeperException, InterruptedException {
return this.zooKeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
/**
* 根据路径获取所有孩子节点
*
* @param path
* @return
* @throws KeeperException
* @throws InterruptedException
*/
public List<String> getChildren(String path) throws KeeperException, InterruptedException {
return this.zooKeeper.getChildren(path, false);
}
public Stat setData(String path, byte[] data, int version) throws KeeperException, InterruptedException {
return this.zooKeeper.setData(path, data, version);
}
/**
* 根据路径获取节点数据
*
* @param path
* @return
* @throws KeeperException
* @throws InterruptedException
*/
public byte[] getData(String path) throws KeeperException, InterruptedException {
return this.zooKeeper.getData(path, false, null);
}
/**
* 删除节点
*
* @param path
* @param version
* @throws InterruptedException
* @throws KeeperException
*/
public void deletNode(String path, int version) throws InterruptedException, KeeperException {
this.zooKeeper.delete(path, version);
}
/**
* 关闭zookeeper连接
*
* @throws InterruptedException
*/
public void closeConnect() throws InterruptedException {
if (null != zooKeeper) {
zooKeeper.close();
}
}
}
package com.test.zk;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class ZookeeperTest {
private static Logger logger = LoggerFactory.getLogger(ZookeeperTest.class);
public static void main(String[] args) {
logger.info("main begin....");
try {
BaseZookeeper baseZookeeper = new BaseZookeeper();
String host = "127.0.0.1:8080";//本地zookeeper端口号改为8080了
// 连接zookeeper
baseZookeeper.connectZookeeper(host);
System.out.println("--------connect zookeeper ok-----------");
// 创建节点
/*byte [] data = {1, 2, 3, 4, 5};
String result = baseZookeeper.createNode("/test", data);
System.out.println(result);
System.out.println("--------create node ok-----------");*/
// 获取某路径下所有节点
List<String> children = baseZookeeper.getChildren("/");
for (String child : children)
{
logger.info(child);
}
logger.info("--------get children ok-----------");
// 获取节点数据
/* byte [] nodeData = baseZookeeper.getData("/test");
logger.info(new String(nodeData,"UTF-8"));
logger.info("--------get node data ok-----------");*/
// 更新节点数据
byte[] data = "测试".getBytes("UTF-8");
baseZookeeper.setData("/test", data, 2);//版本号为当前的版本
System.out.println("--------set node data ok-----------");
byte[] nodeData = baseZookeeper.getData("/test");
System.out.println(new String(nodeData,"UTF-8"));
System.out.println("--------get node new data ok-----------");
baseZookeeper.closeConnect();
System.out.println("--------close zookeeper ok-----------");
} catch (Exception e) {
logger.error("...zookeeper操作出错....",e);
}
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>test-demo</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>test-demo Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<junit.version>3.8.1</junit.version>
<zkclient.version>2.1.1</zkclient.version>
<zookeeper.version>3.4.6</zookeeper.version>
<slf4j-log4j12.version>1.7.12</slf4j-log4j12.version>
</properties>
<dependencies>
<!--
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
-->
<!--
<dependency>
<groupId>com.github.adyliu</groupId>
<artifactId>zkclient</artifactId>
<version>${zkclient.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
<scope>compile</scope>
</dependency>
-->
<!--zookeeper java客户端-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zookeeper.version}</version>
<exclusions>
<exclusion>
<groupId>jline</groupId>
<artifactId>jline</artifactId>
</exclusion>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--日志相关-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-log4j12.version}</version>
</dependency>
</dependencies>
<build>
<finalName>test-demo</finalName>
</build>
</project>
一、ZooKeeper 节点
是有生命周期的,这取决于节点的类型。在 ZooKeeper 中,节点类型可以分为持久节点(PERSISTENT )、临时节点(EPHEMERAL),以及时序节点(SEQUENTIAL ),具体在节点创建过程中,一般是组合使用,可以生成以下 4 种节点类型。
持久节点(PERSISTENT)
所谓持久节点,是指在节点创建后,就一直存在,直到有删除操作来主动清除这个节点——不会因为创建该节点的客户端会话失效而消失。
持久顺序节点(PERSISTENT_SEQUENTIAL)
这类节点的基本特性和上面的节点类型是一致的。额外的特性是,在ZK中,每个父节点会为他的第一级子节点维护一份时序,会记录每个子节点创建的先后顺序。 基于这个特性,在创建子节点的时候,可以设置这个属性,那么在创建节点过程中,ZK会自动为给定节点名加上一个数字后缀,作为新的节点名。这个数字后缀的 范围是整型的最大值。
临时节点(EPHEMERAL)
和持久节点不同的是,临时节点的生命周期和客户端会话绑定。也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。注意,这里提到的是会话失效,而非连接断开。另外,在临时节点下面不能创建子节点。
临时顺序节点(EPHEMERAL_SEQUENTIAL)
可以用来实现分布式锁
客户端调用create()方法创建名为“_locknode_/guid-lock-”的节点,需要注意的是,这里节点的创建类型需要设置为EPHEMERAL_SEQUENTIAL。
客户端调用getChildren(“_locknode_”)方法来获取所有已经创建的子节点,注意,这里不注册任何Watcher。
客户端获取到所有子节点path之后,如果发现自己在步骤1中创建的节点序号最小,那么就认为这个客户端获得了锁。
如果在步骤3中发现自己并非所有子节点中最小的,说明自己还没有获取到锁。此时客户端需要找到比自己小的那个节点,然后对其调用exist()方法,同时注册事件监听。
之后当这个被关注的节点被移除了,客户端会收到相应的通知。这个时候客户端需要再次调用getChildren(“_locknode_”)方法来获取所有已经创建的子节点,确保自己确实是最小的节点了,然后进入步骤3。