Zookeeper 简明教程
Zookeeper - API
ZooKeeper 有一个官方的 Java 和 C API 绑定。ZooKeeper 社区为大多数语言(.NET、python 等)提供非官方 API。使用 ZooKeeper API,应用程序可以连接、交互、操作数据、协调,最后从 ZooKeeper 集群断开连接。
ZooKeeper has an official API binding for Java and C. The ZooKeeper community provides unofficial API for most of the languages (.NET, python, etc.). Using ZooKeeper API, an application can connect, interact, manipulate data, coordinate, and finally disconnect from a ZooKeeper ensemble.
ZooKeeper API 具有丰富的一组功能,可以以一种简单安全的方式获得 ZooKeeper 集群的所有功能。ZooKeeper API 提供同步和异步方法。
ZooKeeper API has a rich set of features to get all the functionality of the ZooKeeper ensemble in a simple and safe manner. ZooKeeper API provides both synchronous and asynchronous methods.
ZooKeeper 集群和 ZooKeeper API 在各个方面都完全相辅相成,极大地有益于开发人员。让我们在本章中讨论 Java 绑定。
ZooKeeper ensemble and ZooKeeper API completely complement each other in every aspect and it benefits the developers in a great way. Let us discuss Java binding in this chapter.
Basics of ZooKeeper API
与 ZooKeeper 集群互动的应用程序称为 ZooKeeper Client 或简称 Client 。
Application interacting with ZooKeeper ensemble is referred as ZooKeeper Client or simply Client.
节点是 ZooKeeper 集群的核心组件,而 ZooKeeper API 提供了一小套方法来使用 ZooKeeper 集群操作所有节点的详细信息。
Znode is the core component of ZooKeeper ensemble and ZooKeeper API provides a small set of methods to manipulate all the details of znode with ZooKeeper ensemble.
要与 ZooKeeper 集合进行清晰简洁的交互,客户端应遵循以下步骤。
A client should follow the steps given below to have a clear and clean interaction with ZooKeeper ensemble.
-
Connect to the ZooKeeper ensemble. ZooKeeper ensemble assign a Session ID for the client.
-
Send heartbeats to the server periodically. Otherwise, the ZooKeeper ensemble expires the Session ID and the client needs to reconnect.
-
Get / Set the znodes as long as a session ID is active.
-
Disconnect from the ZooKeeper ensemble, once all the tasks are completed. If the client is inactive for a prolonged time, then the ZooKeeper ensemble will automatically disconnect the client.
Java Binding
让我们在本节中了解最重要的 ZooKeeper API 集合。ZooKeeper API 的核心部分是 ZooKeeper class 。它提供选项,在其构造函数中连接 ZooKeeper 集合,并具有以下方法:
Let us understand the most important set of ZooKeeper API in this chapter. The central part of the ZooKeeper API is ZooKeeper class. It provides options to connect the ZooKeeper ensemble in its constructor and has the following methods −
-
connect − connect to the ZooKeeper ensemble
-
create − create a znode
-
exists − check whether a znode exists and its information
-
getData − get data from a particular znode
-
setData − set data in a particular znode
-
getChildren − get all sub-nodes available in a particular znode
-
delete − get a particular znode and all its children
-
close − close a connection
Connect to the ZooKeeper Ensemble
ZooKeeper 类通过其构造函数提供连接功能。构造函数的签名如下所示:
The ZooKeeper class provides connection functionality through its constructor. The signature of the constructor is as follows −
ZooKeeper(String connectionString, int sessionTimeout, Watcher watcher)
其中,
Where,
-
connectionString − ZooKeeper ensemble host.
-
sessionTimeout − session timeout in milliseconds.
-
watcher − an object implementing “Watcher” interface. The ZooKeeper ensemble returns the connection status through the watcher object.
让我们创建一个新的帮助程序类 ZooKeeperConnection 并添加一个方法 connect 。 connect 方法创建 ZooKeeper 对象,连接到 ZooKeeper 集合,然后返回对象。
Let us create a new helper class ZooKeeperConnection and add a method connect. The connect method creates a ZooKeeper object, connects to the ZooKeeper ensemble, and then returns the object.
此处 CountDownLatch 用来停止(等待)主进程,直到客户端连接到 ZooKeeper 集群。
Here CountDownLatch is used to stop (wait) the main process until the client connects with the ZooKeeper ensemble.
ZooKeeper 集群通过 Watcher callback 返回连接状态。客户端连接到 ZooKeeper 集群后,将调用 Watcher 回调,并且 Watcher 回调会调用 CountDownLatch 的 countDown 方法来释放 await 中主进程的锁。
The ZooKeeper ensemble replies the connection status through the Watcher callback. The Watcher callback will be called once the client connects with the ZooKeeper ensemble and the Watcher callback calls the countDown method of the CountDownLatch to release the lock, await in the main process.
以下是用于连接到 ZooKeeper 集群的完整代码。
Here is the complete code to connect with a ZooKeeper ensemble.
Coding: ZooKeeperConnection.java
// import java classes
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
// import zookeeper classes
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.AsyncCallback.StatCallback;
import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.data.Stat;
public class ZooKeeperConnection {
// declare zookeeper instance to access ZooKeeper ensemble
private ZooKeeper zoo;
final CountDownLatch connectedSignal = new CountDownLatch(1);
// Method to connect zookeeper ensemble.
public ZooKeeper connect(String host) throws IOException,InterruptedException {
zoo = new ZooKeeper(host,5000,new Watcher() {
public void process(WatchedEvent we) {
if (we.getState() == KeeperState.SyncConnected) {
connectedSignal.countDown();
}
}
});
connectedSignal.await();
return zoo;
}
// Method to disconnect from zookeeper server
public void close() throws InterruptedException {
zoo.close();
}
}
保存以上代码,它将在下一节中用于连接到 ZooKeeper 集群。
Save the above code and it will be used in the next section for connecting the ZooKeeper ensemble.
Create a Znode
ZooKeeper 类提供了 create method 用于在 ZooKeeper 集群中创建新 znode。 create 方法的签名如下 −
The ZooKeeper class provides create method to create a new znode in the ZooKeeper ensemble. The signature of the create method is as follows −
create(String path, byte[] data, List<ACL> acl, CreateMode createMode)
其中,
Where,
-
path − Znode path. For example, /myapp1, /myapp2, /myapp1/mydata1, myapp2/mydata1/myanothersubdata
-
data − data to store in a specified znode path
-
acl − access control list of the node to be created. ZooKeeper API provides a static interface ZooDefs.Ids to get some of basic acl list. For example, ZooDefs.Ids.OPEN_ACL_UNSAFE returns a list of acl for open znodes.
-
createMode − the type of node, either ephemeral, sequential, or both. This is an enum.
让我们创建一个新的 Java 应用程序来检查 ZooKeeper API 的 create 功能。创建一个文件 ZKCreate.java 。在主方法中,创建一个类型为 ZooKeeperConnection 的对象并调用 connect 方法来连接到 ZooKeeper 集群。
Let us create a new Java application to check the create functionality of the ZooKeeper API. Create a file ZKCreate.java. In the main method, create an object of type ZooKeeperConnection and call the connect method to connect to the ZooKeeper ensemble.
connect 方法将返回 ZooKeeper 对象 zk 。现在,使用自定义 path 和 data 调用 zk 对象的 create 方法。
The connect method will return the ZooKeeper object zk. Now, call the create method of zk object with custom path and data.
用于创建 znode 的完整程序代码如下 −
The complete program code to create a znode is as follows −
Coding: ZKCreate.java
import java.io.IOException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
public class ZKCreate {
// create static instance for zookeeper class.
private static ZooKeeper zk;
// create static instance for ZooKeeperConnection class.
private static ZooKeeperConnection conn;
// Method to create znode in zookeeper ensemble
public static void create(String path, byte[] data) throws
KeeperException,InterruptedException {
zk.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
public static void main(String[] args) {
// znode path
String path = "/MyFirstZnode"; // Assign path to znode
// data in byte array
byte[] data = "My first zookeeper app”.getBytes(); // Declare data
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
create(path, data); // Create the data to the specified path
conn.close();
} catch (Exception e) {
System.out.println(e.getMessage()); //Catch error message
}
}
}
一旦编译并执行应用程序,将在 ZooKeeper 集群中创建一个具有指定数据的新 znode。你可以使用 ZooKeeper CLI zkCli.sh 来检查它。
Once the application is compiled and executed, a znode with the specified data will be created in the ZooKeeper ensemble. You can check it using the ZooKeeper CLI zkCli.sh.
cd /path/to/zookeeper
bin/zkCli.sh
>>> get /MyFirstZnode
Exists – Check the Existence of a Znode
ZooKeeper 类提供 exists method 来检查 znode 的存在。如果指定的 znode 存在,它将返回 znode 的元数据。 exists 方法的签名如下 −
The ZooKeeper class provides the exists method to check the existence of a znode. It returns the metadata of a znode, if the specified znode exists. The signature of the exists method is as follows −
exists(String path, boolean watcher)
其中,
Where,
-
path − Znode path
-
watcher − boolean value to specify whether to watch a specified znode or not
让我们创建一个新的 Java 应用程序来检查 ZooKeeper API 的“exists”功能。创建一个文件 “ZKExists.java”。在主方法中,使用 “ZooKeeperConnection” 对象创建一个 ZooKeeper 对象“zk”。然后,使用自定义“path”调用“zk”对象的“exists”方法。完整的清单如下 −
Let us create a new Java application to check the “exists” functionality of the ZooKeeper API. Create a file “ZKExists.java”. In the main method, create ZooKeeper object, “zk” using “ZooKeeperConnection” object. Then, call “exists” method of “zk” object with custom “path”. The complete listing is as follow −
Coding: ZKExists.java
import java.io.IOException;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.data.Stat;
public class ZKExists {
private static ZooKeeper zk;
private static ZooKeeperConnection conn;
// Method to check existence of znode and its status, if znode is available.
public static Stat znode_exists(String path) throws
KeeperException,InterruptedException {
return zk.exists(path, true);
}
public static void main(String[] args) throws InterruptedException,KeeperException {
String path = "/MyFirstZnode"; // Assign znode to the specified path
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
Stat stat = znode_exists(path); // Stat checks the path of the znode
if(stat != null) {
System.out.println("Node exists and the node version is " +
stat.getVersion());
} else {
System.out.println("Node does not exists");
}
} catch(Exception e) {
System.out.println(e.getMessage()); // Catches error messages
}
}
}
一旦编译并执行应用程序,你将获得以下输出。
Once the application is compiled and executed, you will get the below output.
Node exists and the node version is 1.
getData Method
ZooKeeper 类提供了 getData 方法来获取附加在指定 znode 中的数据及其状态。 getData 方法的签名如下 −
The ZooKeeper class provides getData method to get the data attached in a specified znode and its status. The signature of the getData method is as follows −
getData(String path, Watcher watcher, Stat stat)
其中,
Where,
-
path − Znode path.
-
watcher − Callback function of type Watcher. The ZooKeeper ensemble will notify through the Watcher callback when the data of the specified znode changes. This is one-time notification.
-
stat − Returns the metadata of a znode.
我们创建一个新的 Java 应用程序以了解 ZooKeeper API 的 getData 功能。创建文件 ZKGetData.java 。在 main 方法中,使用 he ZooKeeperConnection 对象创建一个 ZooKeeper 对象 zk 。然后,使用自定义路径调用 zk 对象的 getData 方法。
Let us create a new Java application to understand the getData functionality of the ZooKeeper API. Create a file ZKGetData.java. In the main method, create a ZooKeeper object zk using he ZooKeeperConnection object. Then, call the getData method of zk object with custom path.
以下是获取指定节点数据的完整程序代码 -
Here is the complete program code to get the data from a specified node −
Coding: ZKGetData.java
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.data.Stat;
public class ZKGetData {
private static ZooKeeper zk;
private static ZooKeeperConnection conn;
public static Stat znode_exists(String path) throws
KeeperException,InterruptedException {
return zk.exists(path,true);
}
public static void main(String[] args) throws InterruptedException, KeeperException {
String path = "/MyFirstZnode";
final CountDownLatch connectedSignal = new CountDownLatch(1);
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
Stat stat = znode_exists(path);
if(stat != null) {
byte[] b = zk.getData(path, new Watcher() {
public void process(WatchedEvent we) {
if (we.getType() == Event.EventType.None) {
switch(we.getState()) {
case Expired:
connectedSignal.countDown();
break;
}
} else {
String path = "/MyFirstZnode";
try {
byte[] bn = zk.getData(path,
false, null);
String data = new String(bn,
"UTF-8");
System.out.println(data);
connectedSignal.countDown();
} catch(Exception ex) {
System.out.println(ex.getMessage());
}
}
}
}, null);
String data = new String(b, "UTF-8");
System.out.println(data);
connectedSignal.await();
} else {
System.out.println("Node does not exists");
}
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
一旦应用程序编译并执行,您会得到以下输出
Once the application is compiled and executed, you will get the following output
My first zookeeper app
并且应用程序会等待 ZooKeeper 集成的进一步通知。使用 ZooKeeper CLI zkCli.sh 更改指定的 z 节点的数据。
And the application will wait for further notification from the ZooKeeper ensemble. Change the data of the specified znode using ZooKeeper CLI zkCli.sh.
cd /path/to/zookeeper
bin/zkCli.sh
>>> set /MyFirstZnode Hello
现在,应用程序将打印以下输出并退出。
Now, the application will print the following output and exit.
Hello
setData Method
ZooKeeper 类提供 setData 方法来修改附加在指定的 z 节点中的数据。 setData 方法的签名如下 -
The ZooKeeper class provides setData method to modify the data attached in a specified znode. The signature of the setData method is as follows −
setData(String path, byte[] data, int version)
其中,
Where,
-
path − Znode path
-
data − data to store in a specified znode path.
-
version − Current version of the znode. ZooKeeper updates the version number of the znode whenever the data gets changed.
我们现在创建一个新的 Java 应用程序以了解 ZooKeeper API 的 setData 功能。创建文件 ZKSetData.java 。在 main 方法中,使用 ZooKeeperConnection 对象创建一个 ZooKeeper 对象 zk 。然后,使用指定的路径、新数据和节点版本调用 zk 对象的 setData 方法。
Let us now create a new Java application to understand the setData functionality of the ZooKeeper API. Create a file ZKSetData.java. In the main method, create a ZooKeeper object zk using the ZooKeeperConnection object. Then, call the setData method of zk object with the specified path, new data, and version of the node.
以下是修改附加在指定 z 节点中的数据的完整程序代码。
Here is the complete program code to modify the data attached in a specified znode.
Code: ZKSetData.java
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import java.io.IOException;
public class ZKSetData {
private static ZooKeeper zk;
private static ZooKeeperConnection conn;
// Method to update the data in a znode. Similar to getData but without watcher.
public static void update(String path, byte[] data) throws
KeeperException,InterruptedException {
zk.setData(path, data, zk.exists(path,true).getVersion());
}
public static void main(String[] args) throws InterruptedException,KeeperException {
String path= "/MyFirstZnode";
byte[] data = "Success".getBytes(); //Assign data which is to be updated.
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
update(path, data); // Update znode data to the specified path
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
一旦应用程序编译并执行,指定 z 节点的数据将被更改,可以使用 ZooKeeper CLI, zkCli.sh 来检查它。
Once the application is compiled and executed, the data of the specified znode will be changed and it can be checked using the ZooKeeper CLI, zkCli.sh.
cd /path/to/zookeeper
bin/zkCli.sh
>>> get /MyFirstZnode
getChildren Method
ZooKeeper 类提供 getChildren 方法来获取某个特定 z 节点的全部子节点。 getChildren 方法的签名如下 -
The ZooKeeper class provides getChildren method to get all the sub-node of a particular znode. The signature of the getChildren method is as follows −
getChildren(String path, Watcher watcher)
其中,
Where,
-
path − Znode path.
-
watcher − Callback function of type “Watcher”. The ZooKeeper ensemble will notify when the specified znode gets deleted or a child under the znode gets created / deleted. This is a one-time notification.
Coding: ZKGetChildren.java
import java.io.IOException;
import java.util.*;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.data.Stat;
public class ZKGetChildren {
private static ZooKeeper zk;
private static ZooKeeperConnection conn;
// Method to check existence of znode and its status, if znode is available.
public static Stat znode_exists(String path) throws
KeeperException,InterruptedException {
return zk.exists(path,true);
}
public static void main(String[] args) throws InterruptedException,KeeperException {
String path = "/MyFirstZnode"; // Assign path to the znode
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
Stat stat = znode_exists(path); // Stat checks the path
if(stat!= null) {
//“getChildren” method- get all the children of znode.It has two
args, path and watch
List <String> children = zk.getChildren(path, false);
for(int i = 0; i < children.size(); i++)
System.out.println(children.get(i)); //Print children's
} else {
System.out.println("Node does not exists");
}
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
在运行程序之前,让我们使用 ZooKeeper CLI, zkCli.sh 为 /MyFirstZnode 创建两个子节点。
Before running the program, let us create two sub-nodes for /MyFirstZnode using the ZooKeeper CLI, zkCli.sh.
cd /path/to/zookeeper
bin/zkCli.sh
>>> create /MyFirstZnode/myfirstsubnode Hi
>>> create /MyFirstZnode/mysecondsubmode Hi
现在,编译并运行程序将输出创建的上述 z 节点。
Now, compiling and running the program will output the above created znodes.
myfirstsubnode
mysecondsubnode
Delete a Znode
ZooKeeper 类提供 delete 方法来删除指定的 z 节点。 delete 方法的签名如下 -
The ZooKeeper class provides delete method to delete a specified znode. The signature of the delete method is as follows −
delete(String path, int version)
其中,
Where,
-
path − Znode path.
-
version − Current version of the znode.
我们创建一个新的 Java 应用程序以了解 ZooKeeper API 的 delete 功能。创建文件 ZKDelete.java 。在 main 方法中,创建一个 ZooKeeper 对象 zk 使用 ZooKeeperConnection 对象。然后,使用 zk 对象的指定 path 和节点的版本调用 delete 方法。
Let us create a new Java application to understand the delete functionality of the ZooKeeper API. Create a file ZKDelete.java. In the main method, create a ZooKeeper object zk using ZooKeeperConnection object. Then, call the delete method of zk object with the specified path and version of the node.
删除znode的完整程序代码如下所示−
The complete program code to delete a znode is as follows −
Coding: ZKDelete.java
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
public class ZKDelete {
private static ZooKeeper zk;
private static ZooKeeperConnection conn;
// Method to check existence of znode and its status, if znode is available.
public static void delete(String path) throws KeeperException,InterruptedException {
zk.delete(path,zk.exists(path,true).getVersion());
}
public static void main(String[] args) throws InterruptedException,KeeperException {
String path = "/MyFirstZnode"; //Assign path to the znode
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
delete(path); //delete the node with the specified path
} catch(Exception e) {
System.out.println(e.getMessage()); // catches error messages
}
}
}