Перейти к основному содержимому

Начало работы с Java и Zookeeper

· 6 мин. чтения

1. Обзор

Apache ZooKeeper — это служба распределенной координации, упрощающая разработку распределенных приложений. Он используется такими проектами, как Apache Hadoop, HBase и другими , для различных вариантов использования, таких как выбор лидера, управление конфигурацией, координация узлов, управление арендой серверов и т. д.

Узлы в кластере ZooKeeper хранят свои данные в общем иерархическом пространстве имен , похожем на стандартную файловую систему или древовидную структуру данных.

В этой статье мы рассмотрим, как использовать Java API Apache Zookeeper для хранения, обновления и удаления информации, хранящейся в ZooKeeper.

2. Настройка

Последнюю версию Java-библиотеки Apache ZooKeeper можно найти здесь :

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

3. Модель данных ZooKeeper — ZNode

ZooKeeper имеет иерархическое пространство имен, очень похожее на распределенную файловую систему, где он хранит данные координации, такие как информация о состоянии, информация о координации, информация о местоположении и т. д. Эта информация хранится на разных узлах.

Каждый узел в дереве ZooKeeper называется ZNode.

Каждый ZNode поддерживает номера версий и метки времени для любых данных или изменений ACL. Кроме того, это позволяет ZooKeeper проверять кэш и координировать обновления.

4. Установка

4.1. Монтаж

Последнюю версию ZooKeeper можно скачать отсюда . Прежде чем сделать это, нам нужно убедиться, что мы соответствуем системным требованиям, описанным здесь .

4.2. Автономный режим

В этой статье мы будем запускать ZooKeeper в автономном режиме, так как он требует минимальной настройки. Выполните действия, описанные в документации здесь .

Примечание. В автономном режиме репликация отсутствует, поэтому в случае сбоя процесса ZooKeeper служба перестанет работать.

5. Примеры интерфейса командной строки ZooKeeper

Теперь мы будем использовать интерфейс командной строки ZooKeeper (CLI) для взаимодействия с ZooKeeper:

bin/zkCli.sh -server 127.0.0.1:2181

Команда выше запускает автономный экземпляр локально. Давайте теперь посмотрим, как создать ZNode и хранить информацию в ZooKeeper:

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

Мы только что создали ZNode MyFirstZNode в корне иерархического пространства имен ZooKeeper и записали в него ZNodeVal .

Поскольку мы не передали ни одного флага, созданный 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

Мы можем обновить данные существующего ZNode, используя операцию set .

Например:

set /MyFirstZNode ZNodeValUpdated

Это обновит данные в MyFirstZNode с ZNodeVal на ZNodeValUpdated.

6. Пример Java API ZooKeeper

Давайте теперь посмотрим на Java API Zookeeper и создадим узел, обновим узел и получим некоторые данные.

6.1. Java-пакеты

Привязки ZooKeeper Java состоят в основном из двух пакетов Java:

  1. org.apache.zookeeper : определяет основной класс клиентской библиотеки ZooKeeper вместе со многими статическими определениями типов и состояний событий ZooKeeper.
  2. org.apache.zookeeper.data : определяет характеристики, связанные с ZNodes, такие как списки контроля доступа (ACL), идентификаторы, статистика и т. д.

В реализации сервера также используются Java-API ZooKeeper, такие как org.apache.zookeeper.server , org.apache.zookeeper.server.quorum и org.apache.zookeeper.server.upgrade .

Однако они выходят за рамки этой статьи.

6.2. Подключение к экземпляру 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();
}
}

Чтобы использовать службу ZooKeeper, приложение должно сначала создать экземпляр объекта класса ZooKeeper , который является основным классом клиентской библиотеки ZooKeeper .

В методе подключения мы создаем экземпляр класса ZooKeeper . Кроме того, мы зарегистрировали метод обратного вызова для обработки WatchedEvent от ZooKeeper для принятия соединения и, соответственно, завершения метода соединения с использованием метода обратного отсчета CountDownLatch .

После установления соединения с сервером клиенту назначается идентификатор сеанса. Чтобы сеанс оставался действительным, клиент должен периодически отправлять на сервер тактовые импульсы.

Клиентское приложение может вызывать API-интерфейсы ZooKeeper, пока его идентификатор сеанса остается действительным.

6.3. Клиентские операции

Теперь мы создадим интерфейс 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;
}

Давайте теперь посмотрим на реализацию вышеуказанного интерфейса:

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);
}
}

В приведенном выше коде вызовы подключения и отключения делегируются ранее созданному классу ZKConnection . Наш метод create используется для создания ZNode по заданному пути из данных массива байтов. Только для демонстрационных целей мы оставили ACL полностью открытым.

После создания ZNode является постоянным и не удаляется при отключении клиента.

Логика извлечения данных ZNode из ZooKeeper в нашем методе getZNodeData довольно проста. Наконец, с помощью метода обновления мы проверяем наличие ZNode по заданному пути и извлекаем его, если он существует.

Кроме того, для обновления данных мы сначала проверяем наличие ZNode и получаем текущую версию. Затем мы вызываем метод setData с путем к ZNode, данными и текущей версией в качестве параметров. ZooKeeper обновит данные только в том случае, если переданная версия совпадает с последней версией.

7. Заключение

При разработке распределенных приложений Apache ZooKeeper играет важную роль в качестве распределенной службы координации. В частности, для таких случаев использования, как хранение общей конфигурации, выбор главного узла и т. д.

ZooKeeper также предоставляет элегантный API-интерфейс на основе Java, который можно использовать в коде клиентского приложения для беспрепятственного взаимодействия с ZooKeeper ZNodes.

И, как всегда, все исходники для этого туториала можно найти на Github .