Getting Started with Java and Zookeeper – Java和Zookeeper的入门

最后修改: 2018年 3月 22日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Apache ZooKeeper is a distributed coordination service which eases the development of distributed applications. It’s used by projects like Apache Hadoop, HBase and others for different use cases like leader election, configuration management, node coordination, server lease management, etc.

Apache ZooKeeper 是一种分布式协调服务,它可以简化分布式应用程序的开发。它被Apache Hadoop、HBase和其他等项目用于领导选举、配置管理、节点协调、服务器租赁管理等不同用例。

Nodes within ZooKeeper cluster store their data in a shared hierarchal namespace which is similar to a standard file system or a tree data structure.

ZooKeeper集群内的节点在一个共享的分层命名空间中存储它们的数据,这类似于标准的文件系统或树形数据结构。

In this article, we’ll explore how to use Java API of Apache Zookeeper to store, update and delete information stored within ZooKeeper.

在这篇文章中,我们将探讨如何使用Apache Zookeeper的Java API来存储、更新和删除存储在ZooKeeper中的信息。

2. Setup

2.设置

The latest version of the Apache ZooKeeper Java library can be found here:

最新版本的Apache ZooKeeper Java库可以在这里找到。

<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.11</version>
</dependency>

3. ZooKeeper Data Model – ZNode

3.ZooKeeper数据模型 – ZNode

ZooKeeper has a hierarchal namespace, much like a distributed file system where it stores coordination data like status information, coordination information, location information, etc. This information is stored on different nodes.

ZooKeeper有一个分层的命名空间,很像一个分布式文件系统,它在这里存储协调数据,如状态信息、协调信息、位置信息等。这些信息被存储在不同的节点上。

Every node in a ZooKeeper tree is referred to as ZNode.

ZooKeeper树中的每个节点都被称为ZNode.

Each ZNode maintains version numbers and timestamps for any data or ACL changes. Also, this allows ZooKeeper to validate the cache and to coordinate updates.

每个ZNode都会维护任何数据或ACL变化的版本号和时间戳。同时,这也使得ZooKeeper能够验证缓存并协调更新。

4. Installation

4.安装

4.1. Installation

4.1.安装

Latest ZooKeeper release can be downloaded from here. Before doing that we need to make sure we meet the system requirements described here.

最新的ZooKeeper版本可以从这里下载。在这之前,我们需要确保我们符合这里所述的系统要求。

4.2. Standalone Mode

4.2.独立模式

For this article, we’ll be running ZooKeeper in a standalone mode as it requires minimal configuration. Follow the steps described in the documentation here.

在本文中,我们将以独立模式运行ZooKeeper,因为它需要最小的配置。按照文档这里中描述的步骤进行。

Note: In standalone mode, there’s no replication so if ZooKeeper process fails, the service will go down.

注意:在独立模式下,没有复制,所以如果ZooKeeper进程失败,服务就会中断。

5. ZooKeeper CLI Examples

5.ZooKeeper CLI实例

We’ll now use the ZooKeeper Command Line Interface (CLI) to interact with ZooKeeper:

现在我们将使用ZooKeeper命令行界面(CLI)来与ZooKeeper进行交互。

bin/zkCli.sh -server 127.0.0.1:2181

Above command starts a standalone instance locally. Let’s now look at how to create a ZNode and store information within ZooKeeper:

上述命令在本地启动一个独立的实例。现在让我们来看看如何在ZooKeeper中创建一个ZNode并存储信息。

[zk: localhost:2181(CONNECTED) 0] create /MyFirstZNode ZNodeVal
Created /FirstZnode

We just created a ZNode ‘MyFirstZNode’ at the root of ZooKeeper hierarchical namespace and written ‘ZNodeVal’ to it.

我们刚刚在ZooKeeper分层命名空间的根部创建了一个ZNode ‘MyFirstZNode’,并将‘ZNodeVal’写到它。

Since we’ve not passed any flag, a created ZNode will be persistent.

由于我们没有传递任何标志,创建的ZNode将是持久的。

Let’s now issue a ‘get’ command to fetch the data as well as metadata associated with a ZNode:

现在让我们发布一个‘get’命令来获取与ZNode相关的数据和元数据。

[zk: localhost:2181(CONNECTED) 1] get /FirstZnode

“Myfirstzookeeper-app”
cZxid = 0x7f
ctime = Sun Feb 18 16:15:47 IST 2018
mZxid = 0x7f
mtime = Sun Feb 18 16:15:47 IST 2018
pZxid = 0x7f
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 22
numChildren = 0

We can update the data of an existing ZNode using the set operation.

我们可以使用set操作更新现有ZNode的数据。

For example:

比如说。

set /MyFirstZNode ZNodeValUpdated

This will update the data at MyFirstZNode from ZNodeVal to ZNodeValUpdated.

这将更新MyFirstZNode的数据,从ZNodeValZNodeValUpdated。

6. ZooKeeper Java API Example

6.ZooKeeper Java API实例

Let’s now look at Zookeeper Java API and create a node, update the node and retrieve some data.

现在让我们看看Zookeeper的Java API,并创建一个节点,更新节点和检索一些数据。

6.1. Java Packages

6.1.Java包

The ZooKeeper Java bindings are composed mainly of two Java packages:

ZooKeeper的Java绑定主要由两个Java包组成。

  1. org.apache.zookeeper: which defines the main class of the ZooKeeper client library along with many static definitions of the ZooKeeper event types and states
  2. org.apache.zookeeper.data: that defines the characteristics associated with ZNodes, such as Access Control Lists (ACL), IDs, stats, and so on

There’s also ZooKeeper Java APIs are used in server implementation such as org.apache.zookeeper.server, org.apache.zookeeper.server.quorum, and org.apache.zookeeper.server.upgrade.

还有ZooKeeper的Java API用于服务器的实现,如org.apache.zookeeper.server, org.apache.zookeeper.server.quorum, 和org.apache.zookeeper.server.upgrade

However, they’re beyond the scope of this article.

然而,它们超出了本文的范围。

6.2. Connecting to a ZooKeeper Instance

6.2.连接到一个ZooKeeper实例

Let’s now create ZKConnection class which will be used to connect and disconnect from an already running ZooKeeper:

现在让我们创建ZKConnection类,它将被用来连接和断开已经运行的ZooKeeper。

public class ZKConnection {
    private ZooKeeper zoo;
    CountDownLatch connectionLatch = new CountDownLatch(1);

    // ...

    public ZooKeeper connect(String host) 
      throws IOException, 
      InterruptedException {
        zoo = new ZooKeeper(host, 2000, new Watcher() {
            public void process(WatchedEvent we) {
                if (we.getState() == KeeperState.SyncConnected) {
                    connectionLatch.countDown();
                }
            }
        });

        connectionLatch.await();
        return zoo;
    }

    public void close() throws InterruptedException {
        zoo.close();
    }
}

To use a ZooKeeper service, an application must first instantiate an object of ZooKeeper class, which is the main class of ZooKeeper client library.

要使用ZooKeeper服务,应用程序必须首先实例化一个ZooKeeper类的对象,它是ZooKeeper客户端库的主类

In connect method, we’re instantiating an instance of ZooKeeper class. Also, we’ve registered a callback method to process the WatchedEvent from ZooKeeper for connection acceptance and accordingly finish the connect method using countdown method of CountDownLatch.

connect方法中,我们正在实例化一个ZooKeeper类的实例。此外,我们还注册了一个回调方法来处理来自ZooKeeper的WatchedEvent以接受连接,并相应地使用CountDownLatchcountdown方法完成connect方法。

Once a connection to a server is established, a session ID gets assigned to the client. To keep the session valid, the client should periodically send heartbeats to the server.

一旦与服务器的连接建立起来,就会给客户端分配一个会话ID。为了保持会话的有效性,客户端应定期向服务器发送心跳。

The client application can call ZooKeeper APIs as long as its session ID remains valid.

只要客户端应用程序的会话ID保持有效,就可以调用ZooKeeper API。

6.3. Client Operations

6.3.客户端操作

We’ll now create a ZKManager interface which exposes different operations like creating a ZNode and saving some data, fetching and updating the ZNode Data:

我们现在将创建一个ZKManager接口,它暴露了不同的操作,如创建一个ZNode并保存一些数据,获取和更新ZNode数据。

public interface ZKManager {
    public void create(String path, byte[] data)
      throws KeeperException, InterruptedException;
    public Object getZNodeData(String path, boolean watchFlag);
    public void update(String path, byte[] data) 
      throws KeeperException, InterruptedException;
}

Let’s now look at the implementation of the above interface:

现在我们来看看上述接口的实现。

public class ZKManagerImpl implements ZKManager {
    private static ZooKeeper zkeeper;
    private static ZKConnection zkConnection;

    public ZKManagerImpl() {
        initialize();
    }

    private void initialize() {
        zkConnection = new ZKConnection();
        zkeeper = zkConnection.connect("localhost");
    }

    public void closeConnection() {
        zkConnection.close();
    }

    public void create(String path, byte[] data) 
      throws KeeperException, 
      InterruptedException {
 
        zkeeper.create(
          path, 
          data, 
          ZooDefs.Ids.OPEN_ACL_UNSAFE, 
          CreateMode.PERSISTENT);
    }

    public Object getZNodeData(String path, boolean watchFlag) 
      throws KeeperException, 
      InterruptedException {
 
        byte[] b = null;
        b = zkeeper.getData(path, null, null);
        return new String(b, "UTF-8");
    }

    public void update(String path, byte[] data) throws KeeperException, 
      InterruptedException {
        int version = zkeeper.exists(path, true).getVersion();
        zkeeper.setData(path, data, version);
    }
}

In the above code, connect and disconnect calls are delegated to the earlier created ZKConnection class. Our create method is used to create a ZNode at given path from the byte array data. For demonstration purpose only, we’ve kept ACL completely open.

在上面的代码中,connectdisconnect调用被委托给先前创建的ZKConnection类。我们的create方法被用来从字节数组数据在给定的路径上创建一个ZNode。仅为演示目的,我们保持ACL完全开放。

Once created, the ZNode is persistent and doesn’t get deleted when the client disconnects.

一旦创建,ZNode是持久的,在客户端断开连接时不会被删除。

The logic to fetch ZNode data from ZooKeeper in our getZNodeData method is quite straightforward. Finally, with the update method, we’re checking the presence of ZNode on given path and fetching it if it exists.

在我们的getZNodeData方法中,从ZooKeeper获取ZNode数据的逻辑是非常直接的。最后,通过update方法,我们要检查给定路径上的ZNode是否存在,如果存在的话,就取回它。

Beyond that, for updating the data, we first check for ZNode existence and get the current version. Then, we invoke the setData method with the path of ZNode, data and current version as parameters. ZooKeeper will update the data only if the passed version matches with the latest version.

除此之外,为了更新数据,我们首先检查ZNode是否存在,并获得当前版本。然后,我们调用setData方法,将ZNode的路径、数据和当前版本作为参数。ZooKeeper只有在传递的版本与最新版本相匹配时才会更新数据。

7. Conclusion

7.结论

When developing distributed applications, Apache ZooKeeper plays a critical role as a distributed coordination service. Specifically for use cases like storing shared configuration, electing the master node, and so on.

在开发分布式应用程序时,Apache ZooKeeper作为分布式协调服务发挥了关键作用。特别是对于存储共享配置、选举主节点等用例。

ZooKeeper also provides an elegant Java-based API’s to be used in client-side application code for seamless communication with ZooKeeper ZNodes.

ZooKeeper还提供了优雅的基于Java的API,可用于客户端应用程序代码,以便与ZooKeeper ZNodes进行无缝通信。

And as always, all sources for this tutorial can be found over on Github.

一如既往,本教程的所有资料都可以在Github上找到