Erste Schritte mit Java und Zookeeper

1. Übersicht

Apache ZooKeeper ist ein verteilter Koordinierungsdienst, der die Entwicklung verteilter Anwendungen erleichtert. Es wird von Projekten wie Apache Hadoop, HBase und anderen für verschiedene Anwendungsfälle wie Leader-Wahl, Konfigurationsmanagement, Knotenkoordination, Server-Lease-Management usw. verwendet.

Knoten im ZooKeeper-Cluster speichern ihre Daten in einem gemeinsam genutzten hierarchischen Namespace, der einem Standarddateisystem oder einer Baumdatenstruktur ähnelt.

In diesem Artikel erfahren Sie, wie Sie die Java-API von Apache Zookeeper zum Speichern, Aktualisieren und Löschen von in ZooKeeper gespeicherten Informationen verwenden.

2. Setup

Die neueste Version der Apache ZooKeeper Java-Bibliothek finden Sie hier:

 org.apache.zookeeper zookeeper 3.4.11 

3. ZooKeeper-Datenmodell - ZNode

ZooKeeper verfügt über einen hierarchischen Namespace, ähnlich wie ein verteiltes Dateisystem, in dem Koordinationsdaten wie Statusinformationen, Koordinationsinformationen, Standortinformationen usw. gespeichert werden. Diese Informationen werden auf verschiedenen Knoten gespeichert.

Jeder Knoten in einem ZooKeeper-Baum wird als ZNode bezeichnet.

Jeder ZNode verwaltet Versionsnummern und Zeitstempel für Daten- oder ACL-Änderungen. Auf diese Weise kann ZooKeeper auch den Cache validieren und Aktualisierungen koordinieren.

4. Installation

4.1. Installation

Die neueste Version von ZooKeeper kann hier heruntergeladen werden. Bevor wir dies tun, müssen wir sicherstellen, dass wir die hier beschriebenen Systemanforderungen erfüllen.

4.2. Standalone-Modus

In diesem Artikel wird ZooKeeper in einem eigenständigen Modus ausgeführt, da nur eine minimale Konfiguration erforderlich ist. Befolgen Sie die in der Dokumentation hier beschriebenen Schritte.

Hinweis: Im Standalone-Modus findet keine Replikation statt. Wenn der ZooKeeper-Prozess fehlschlägt, fällt der Dienst aus.

5. ZooKeeper CLI-Beispiele

Wir werden jetzt die ZooKeeper-Befehlszeilenschnittstelle (CLI) verwenden, um mit ZooKeeper zu interagieren:

bin/zkCli.sh -server 127.0.0.1:2181

Der obige Befehl startet lokal eine eigenständige Instanz. Schauen wir uns nun an, wie Sie einen ZNode erstellen und Informationen in ZooKeeper speichern:

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

Wir haben gerade einen ZNode 'MyFirstZNode' im Stammverzeichnis des hierarchischen ZooKeeper-Namespace erstellt und 'ZNodeVal' darauf geschrieben.

Da wir kein Flag übergeben haben, bleibt ein erstellter ZNode bestehen.

Lassen Sie uns nun einen ' get' - Befehl ausgeben , um die Daten sowie die mit einem ZNode verknüpften Metadaten abzurufen:

[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

Wir können die Daten eines vorhandenen ZNode mit der Set- Operation aktualisieren .

Zum Beispiel:

set /MyFirstZNode ZNodeValUpdated

Dadurch werden die Daten bei MyFirstZNode von ZNodeVal auf ZNodeValUpdated aktualisiert.

6. ZooKeeper Java API Beispiel

Schauen wir uns nun die Zookeeper Java API an und erstellen einen Knoten, aktualisieren den Knoten und rufen einige Daten ab.

6.1. Java-Pakete

Die ZooKeeper Java-Bindungen bestehen hauptsächlich aus zwei Java-Paketen:

  1. org.apache.zookeeper : Definiert die Hauptklasse der ZooKeeper-Clientbibliothek zusammen mit vielen statischen Definitionen der ZooKeeper-Ereignistypen und -Zustände
  2. org.apache.zookeeper.data : Definiert die mit ZNodes verknüpften Merkmale wie Zugriffssteuerungslisten (ACL), IDs, Statistiken usw.

Es gibt auch ZooKeeper Java-APIs, die in der Serverimplementierung verwendet werden, z. B. org.apache.zookeeper.server , org.apache.zookeeper.server.quorum und org.apache.zookeeper.server.upgrade .

Sie gehen jedoch über den Rahmen dieses Artikels hinaus.

6.2. Herstellen einer Verbindung zu einer ZooKeeper-Instanz

Lassen Sie uns nun eine ZKConnection- Klasse erstellen , die zum Verbinden und Trennen von einem bereits laufenden ZooKeeper verwendet wird:

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

Um einen ZooKeeper-Dienst verwenden zu können, muss eine Anwendung zuerst ein Objekt der ZooKeeper- Klasse instanziieren , die die Hauptklasse der ZooKeeper-Clientbibliothek ist .

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.

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.

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

6.3. Client Operations

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:

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.

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

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.

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.

7. Conclusion

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.

ZooKeeper bietet auch eine elegante Java-basierte API, die im clientseitigen Anwendungscode für die nahtlose Kommunikation mit ZooKeeper ZNodes verwendet werden kann.

Und wie immer finden Sie alle Quellen für dieses Tutorial auf Github.