ZooKeeper集群中,客户端可以对ZooKeeper的命名空间写入数据,对数据进行各种操作。ZooKeeper API 接口如下表所示:
操作接口名称 描述
create 创建指定的ZooKeeper命名空间(PATH)数据。
delete 创建指定的ZooKeeper命名空间(PATH)数据。
exists 检测节点是否存在
getChildren 获取节点孩子列表
getData 获取指定节点数据
setData 设置指定节点的数据
getACL 获取节点的ACL
setACL 设置节点的ACL
sync 同步一个客户视图到ZooKeeper中
1.4.1 增删改查
给指定ZooKeeper命名空间创建节点,你可以扩展ZooKeeper类。你可以定义类ZooKeeperRetry,然后定义构造方法。
/**
* @param connectString ZooKeeper‘s host and port 字符串表达
* @param sessionTimeout 连接超时时间
* @param watcher 观察者对象
* @throws IOException
*/
public ZooKeeperRetry(String connectString, int sessionTimeout,
Watcher watcher) throws IOException {
super(connectString, sessionTimeout, watcher);
this.watcher = watcher;
}
复写ZooKeeper类的方法。对于添加操作API,复写对应的create方法,定义个性化地创建节点操作。
@Override
public String create(String path, byte[] data, List<ACL> acl,
CreateMode createMode) throws KeeperException, InterruptedException {
int count = 0;
do {
try {
return super.create(path, data, acl, createMode);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
if (exists(path, false) != null) {
return path;
}
} catch (KeeperException.NodeExistsException e) {
return path;
}
} while (!closed && (limit == -1 || count++ < limit));
return null;
}
对于修改操作,使用创建方法去完成更新,即存在的节点内容被新节点信息所覆盖。对于删除操作,直接复写ZooKeeper的delete方法,下面的代码实现了删除节点操作。如果操作失败,它会自动重复尝试3次,直到成功为止。
/**
*
* @param path
* the path of the node to be deleted.
* @param version
* the expected node version.
* @throws InterruptedException
* @throws KeeperException
*/
@Override
public void delete(String path, int version) throws InterruptedException,
KeeperException {
int count = 0;
do {
try {
super.delete(path, version);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
if (exists(path, false) == null) {
return;
}
} catch (KeeperException.NoNodeException e) {
break;
}
} while (!closed && (limit == -1 || count++ < limit));
}
为了加深理解,下面将给一个例子。
建立一个maven项目,添加下面的maven依赖配置。
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.6</version>
</dependency>
定义ZooKeeper的扩展类ZooKeeperRobot类,文件代码如下所示:
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.inspector.logger.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* A Class which extends {@link ZooKeeper} and will automatically retry calls to
* zookeeper if a {@link KeeperException.ConnectionLossException} occurs
*/
public class ZooKeeperRobot extends ZooKeeper {
private boolean closed = false;
private final Watcher watcher;
private int limit = -1;
/**
* @param connectString ZooKeeper‘s host and port 字符串表达
* @param sessionTimeout 连接超时时间
* @param watcher 观察者对象
* @throws IOException
*/
public ZooKeeperRobot(String connectString, int sessionTimeout,
Watcher watcher) throws IOException {
super(connectString, sessionTimeout, watcher);
this.watcher = watcher;
}
/**
* @param connectString
* @param sessionTimeout
* @param watcher
* @param sessionId
* @param sessionPasswd
* @throws IOException
*/
public ZooKeeperRobot(String connectString, int sessionTimeout,
Watcher watcher, long sessionId, byte[] sessionPasswd)
throws IOException {
super(connectString, sessionTimeout, watcher, sessionId, sessionPasswd);
this.watcher = watcher;
}
@Override
public synchronized void close() throws InterruptedException {
this.closed = true;
super.close();
}
/**
* * @param path
* the path for the node
* @param data
* the initial data for the node
* @param acl
* the acl for the node
* @param createMode
* specifying whether the node to be created is ephemeral
* and/or sequential
* @return the actual path of the created node
* @throws KeeperException
* @throws InterruptedException
*/
@Override
public String create(String path, byte[] data, List<ACL> acl,
CreateMode createMode) throws KeeperException, InterruptedException {
int count = 0;
do {
try {
return super.create(path, data, acl, createMode);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect."+e.getMessage());
if (exists(path, false) != null) {
return path;
}
} catch (KeeperException.NodeExistsException e) {
LoggerFactory.getLogger().warn(
"NodeExistsException:."+e.getMessage());
return path;
}catch(KeeperException.NoNodeException e){
LoggerFactory.getLogger().warn(
"NoNodeException:."+e.getMessage());
return path;
}
} while (!closed && (limit == -1 || count++ < limit));
return null;
}
/**
* * @param path
* the path for the node
* @param data
* the initial data for the node
* @param acl
* the acl for the node
* @param createMode
* specifying whether the node to be created is ephemeral
* and/or sequential
* @return the actual path of the created node
* @throws KeeperException
* @throws InterruptedException
*/
public String createPersistent(String path, byte[] data, List<ACL> acl,
CreateMode createMode) throws KeeperException, InterruptedException {
int count = 0;
String[] partsPath = path.split("/");
int checkSize = partsPath.length - 1;
for(int i = 0; i< checkSize; i++){
String prefixMark = "";
for(int j = 0; j <= i; j++){
prefixMark += partsPath[j] + "/";
}
if(prefixMark.length() != 1){
prefixMark = prefixMark.substring(0, prefixMark.length()-1);
if(exists(prefixMark, false) == null){
LoggerFactory.getLogger().warn("create namespace: " + super.create(prefixMark, "".getBytes(), acl, createMode));
}
}
}
do {
try {
return super.create(path, data, acl, createMode);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect."+e.getMessage());
if (exists(path, false) != null) {
return path;
}
} catch (KeeperException.NodeExistsException e) {
LoggerFactory.getLogger().warn(
"NodeExistsException:."+e.getMessage());
return path;
}catch(KeeperException.NoNodeException e){
LoggerFactory.getLogger().warn(
"NoNodeException:."+e.getMessage());
}
} while (!closed && (limit == -1 || count++ < limit));
return null;
}
/**
*
* @param path
* the path of the node to be deleted.
* @param version
* the expected node version.
* @throws InterruptedException
* @throws KeeperException
*/
@Override
public void delete(String path, int version) throws InterruptedException,
KeeperException {
int count = 0;
do {
try {
super.delete(path, version);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
if (exists(path, false) == null) {
return;
}
} catch (KeeperException.NoNodeException e) {
break;
}
} while (!closed && (limit == -1 || count++ < limit));
}
@Override
public Stat exists(String path, boolean watch) throws KeeperException,
InterruptedException {
int count = 0;
do {
try {
return super.exists(path, watch ? watcher : null);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
}
} while (!closed && (limit == -1 || count++ < limit));
return null;
}
@Override
public Stat exists(String path, Watcher watcher) throws KeeperException,
InterruptedException {
int count = 0;
do {
try {
return super.exists(path, watcher);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
}
} while (!closed && (limit == -1 || count++ < limit));
return null;
}
@Override
public List<ACL> getACL(String path, Stat stat) throws KeeperException,
InterruptedException {
int count = 0;
do {
try {
return super.getACL(path, stat);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
}
} while (!closed && (limit == -1 || count++ < limit));
return null;
}
@Override
public List<String> getChildren(String path, boolean watch)
throws KeeperException, InterruptedException {
int count = 0;
do {
try {
return super.getChildren(path, watch ? watcher : null);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
}
} while (!closed && (limit == -1 || count++ < limit));
return new ArrayList<String>();
}
@Override
public List<String> getChildren(String path, Watcher watcher)
throws KeeperException, InterruptedException {
int count = 0;
do {
try {
return super.getChildren(path, watcher);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
}
} while (!closed && (limit == -1 || count++ < limit));
return new ArrayList<String>();
}
@Override
public byte[] getData(String path, boolean watch, Stat stat)
throws KeeperException, InterruptedException {
int count = 0;
do {
try {
return super.getData(path, watch ? watcher : null, stat);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
}
} while (!closed && (limit == -1 || count++ < limit));
return null;
}
@Override
public byte[] getData(String path, Watcher watcher, Stat stat)
throws KeeperException, InterruptedException {
int count = 0;
do {
try {
return super.getData(path, watcher, stat);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
}
} while (!closed && (limit == -1 || count++ < limit));
return null;
}
@Override
public Stat setACL(String path, List<ACL> acl, int version)
throws KeeperException, InterruptedException {
int count = 0;
do {
try {
return super.setACL(path, acl, version);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
Stat s = exists(path, false);
if (s != null) {
if (getACL(path, s).equals(acl)) {
return s;
}
} else {
return null;
}
}
} while (!closed && (limit == -1 || count++ < limit));
return null;
}
@Override
public Stat setData(String path, byte[] data, int version)
throws KeeperException, InterruptedException {
int count = 0;
do {
try {
return super.setData(path, data, version);
} catch (KeeperException.ConnectionLossException e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
Stat s = exists(path, false);
if (s != null) {
if (getData(path, false, s) == data) {
return s;
}
} else {
return null;
}
}
} while (!closed && (limit == -1 || count++ < limit));
return null;
}
/**
* @param limit
*/
public void setRetryLimit(int limit) {
this.limit = limit;
}
/**
* @return true if successfully connected to zookeeper
*/
public boolean testConnection() {
int count = 0;
do {
try {
return super.exists("/", null) != null;
} catch (Exception e) {
LoggerFactory.getLogger().warn(
"ZooKeeper connection lost. Trying to reconnect.");
}
} while (count++ < 3);
return false;
}
}
对于的测试类ZooKeeperRobotTest。
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.IOException;
import java.util.List;
/**
* @author elite_jigang@163.com
*/
public class ZooKeeperRobotTest {
private final static String ZOO_KEEPER_ADDRESS = "192.168.115.15:2222,192.168.115.2:2222,192.168.115.20:2222";
private boolean connected = true;
private ZooKeeper zooKeeper;
@Test
public void testCreatePersistent() throws IOException, KeeperException, InterruptedException {
zooKeeper= new ZooKeeperRobot(ZOO_KEEPER_ADDRESS, 3000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.Expired) {
connected = false;
}
}
});
((ZooKeeperRobot)zooKeeper).setRetryLimit(3);
System.out.println("connect to ZooKeeper servers : " + ((ZooKeeperRobot) zooKeeper).testConnection());
String data = "HBase, SolrCloud,Kafka";
String nodePath1 = "/root2/node_b";
String[] partsPath = nodePath1.split("/");
int checkSize = partsPath.length - 1;
for(int i = 0; i< checkSize; i++){
String prefixMark = "";
for(int j = 0; j <= i; j++){
prefixMark += partsPath[j] + "/";
}
if(prefixMark.length() != 1){
prefixMark = prefixMark.substring(0, prefixMark.length()-1);
Stat stat = ((ZooKeeperRobot)zooKeeper).exists(prefixMark, false);
if(stat == null){
((ZooKeeperRobot)zooKeeper).create(prefixMark, "12333333".getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
}
}
Stat stat = ((ZooKeeperRobot)zooKeeper).exists(nodePath1, null);
if(stat == null){
String result1 = ((ZooKeeperRobot)zooKeeper).createPersistent(nodePath1,
data.getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
System.out.println("-------" + result1);
Assert.assertEquals(result1, nodePath1);
}
System.out.println("-------");
((ZooKeeperRobot)zooKeeper).close();
}
@org.testng.annotations.Test
public void testCreatePersistentNode1() throws Exception {
ZooKeeper zooKeeper= new ZooKeeperRobot(
ZOO_KEEPER_ADDRESS, 3000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.Expired) {
connected = false;
}
}
});
((ZooKeeperRobot)zooKeeper).setRetryLimit(3);
System.out.println("connect to ZooKeeper servers : " + ((ZooKeeperRobot) zooKeeper).testConnection());
String data = "HBase, SolrCloud,Kafka";
String nodePath1 = "/root/node_b";
String firstPath2 = "/root";
String result1 = ((ZooKeeperRobot)zooKeeper).create(firstPath2,
"123".getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
System.out.println("-------" + result1);
Assert.assertEquals(result1, firstPath2);
Stat stat = ((ZooKeeperRobot)zooKeeper).exists(nodePath1, null);
if(stat == null){
result1 = ((ZooKeeperRobot)zooKeeper).create(firstPath2,
data.getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
System.out.println("-------" + result1);
Assert.assertEquals(result1, nodePath1);
}
System.out.println("-------");
((ZooKeeperRobot)zooKeeper).close();
}
@org.testng.annotations.Test
public void testDelete() throws Exception {
zooKeeper= new ZooKeeperRobot(ZOO_KEEPER_ADDRESS, 3000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.Expired) {
connected = false;
}
}
});
((ZooKeeperRobot)zooKeeper).setRetryLimit(3);
System.out.println("connect to ZooKeeper servers : " + ((ZooKeeperRobot) zooKeeper).testConnection());
String nodePath1 = "/root/node_b";
String nodePath2 = "/root2/node_b";
String nodePath3 = "/root";
String nodePath4 = "/root2";
((ZooKeeperRobot)zooKeeper).delete(nodePath1, -1);
((ZooKeeperRobot)zooKeeper).delete(nodePath2, -1);
((ZooKeeperRobot)zooKeeper).delete(nodePath3, -1);
((ZooKeeperRobot)zooKeeper).delete(nodePath4, -1);
}
@org.testng.annotations.Test
public void testGetACL() throws Exception {
zooKeeper= new ZooKeeperRobot(ZOO_KEEPER_ADDRESS, 3000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.Expired) {
connected = false;
}
}
});
((ZooKeeperRobot)zooKeeper).setRetryLimit(3);
System.out.println("connect to ZooKeeper servers : " + ((ZooKeeperRobot) zooKeeper).testConnection());
String nodePath1 = "/root1/node_b";
List<ACL> list = ((ZooKeeperRobot)zooKeeper).getACL(nodePath1, new Stat());
for(ACL acl: list){
System.out.println(" acl:"+ acl);
}
}
@org.testng.annotations.Test
public void testGetChildren() throws Exception {
ZooKeeper zooKeeper = null;
try {
zooKeeper =
new ZooKeeperRobot(ZOO_KEEPER_ADDRESS,
3000, // millisecond
new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.Expired) {
connected = false;
}
}
});
((ZooKeeperRobot) zooKeeper).setRetryLimit(3);
connected = ((ZooKeeperRobot)zooKeeper).testConnection();
System.out.println(" connect to zookeeper : "+ connected);
Stat stat = new Stat();
String path = "/test";
try {
List<String> childs = zooKeeper.getChildren(path, false, stat);
for(String node: childs){
System.out.println("\t"+ node);
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@org.testng.annotations.Test
public void testGetData() throws Exception {
zooKeeper= new ZooKeeperRobot(ZOO_KEEPER_ADDRESS, 3000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.Expired) {
connected = false;
}
}
});
((ZooKeeperRobot)zooKeeper).setRetryLimit(3);
System.out.println("connect to ZooKeeper servers : " + ((ZooKeeperRobot) zooKeeper).testConnection());
String nodePath1 = "/root1/node_b";
System.out.println("----"+ new String(((ZooKeeperRobot) zooKeeper).getData(nodePath1, false, new Stat())));
}
@org.testng.annotations.Test
public void testSetACL() throws Exception {
}
@org.testng.annotations.Test
public void testSetData() throws Exception {
zooKeeper= new ZooKeeperRobot(ZOO_KEEPER_ADDRESS, 3000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == Event.KeeperState.Expired) {
connected = false;
}
}
});
((ZooKeeperRobot)zooKeeper).setRetryLimit(3);
System.out.println("connect to ZooKeeper servers : " + ((ZooKeeperRobot) zooKeeper).testConnection());
String nodePath1 = "/root1/node_b";
System.out.println("----"+ ((ZooKeeperRobot) zooKeeper).setData(nodePath1, "2222222".getBytes(), -1));
System.out.println("*****" + new String(((ZooKeeperRobot) zooKeeper).getData(nodePath1, false, new Stat())));
}
}
欢迎关注我的微信公众号