Premiers pas avec Java et Zookeeper

1. Vue d'ensemble

Apache ZooKeeper est un service de coordination distribué qui facilite le développement d'applications distribuées. Il est utilisé par des projets comme Apache Hadoop, HBase et d'autres pour différents cas d'utilisation tels que l'élection de leader, la gestion de la configuration, la coordination des nœuds, la gestion des locations de serveurs, etc.

Les nœuds du cluster ZooKeeper stockent leurs données dans un espace de noms hiérarchique partagé qui est similaire à un système de fichiers standard ou à une structure de données arborescente.

Dans cet article, nous allons explorer comment utiliser l'API Java d'Apache Zookeeper pour stocker, mettre à jour et supprimer les informations stockées dans ZooKeeper.

2. Configuration

La dernière version de la bibliothèque Java Apache ZooKeeper peut être trouvée ici:

 org.apache.zookeeper zookeeper 3.4.11 

3. Modèle de données ZooKeeper - ZNode

ZooKeeper a un espace de noms hiérarchique, un peu comme un système de fichiers distribué où il stocke des données de coordination comme les informations d'état, les informations de coordination, les informations de localisation, etc. Ces informations sont stockées sur différents nœuds.

Chaque nœud d'une arborescence ZooKeeper est appelé ZNode.

Chaque ZNode conserve les numéros de version et les horodatages pour toutes les données ou modifications d'ACL. En outre, cela permet à ZooKeeper de valider le cache et de coordonner les mises à jour.

4. Installation

4.1. Installation

La dernière version de ZooKeeper peut être téléchargée ici. Avant de faire cela, nous devons nous assurer que nous respectons la configuration système requise décrite ici.

4.2. Mode autonome

Pour cet article, nous allons exécuter ZooKeeper en mode autonome car il nécessite une configuration minimale. Suivez les étapes décrites dans la documentation ici.

Remarque: en mode autonome, il n'y a pas de réplication, donc si le processus ZooKeeper échoue, le service s'arrêtera.

5. Exemples de CLI ZooKeeper

Nous allons maintenant utiliser l'interface de ligne de commande (CLI) ZooKeeper pour interagir avec ZooKeeper:

bin/zkCli.sh -server 127.0.0.1:2181

La commande ci-dessus démarre une instance autonome localement. Voyons maintenant comment créer un ZNode et stocker des informations dans ZooKeeper:

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

Nous venons de créer un ZNode 'MyFirstZNode' à la racine de l'espace de noms hiérarchique ZooKeeper et y avons écrit 'ZNodeVal' .

Puisque nous n'avons passé aucun drapeau, un ZNode créé sera persistant.

Lançons maintenant une commande 'get' pour récupérer les données ainsi que les métadonnées associées à un 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

Nous pouvons mettre à jour les données d'un ZNode existant en utilisant l' opération set .

Par exemple:

set /MyFirstZNode ZNodeValUpdated

Cela mettra à jour les données de MyFirstZNode de ZNodeVal vers ZNodeValUpdated.

6. Exemple d'API Java ZooKeeper

Regardons maintenant l'API Java de Zookeeper et créons un nœud, mettons à jour le nœud et récupérons des données.

6.1. Paquets Java

Les liaisons Java ZooKeeper sont composées principalement de deux packages Java:

  1. org.apache.zookeeper : qui définit la classe principale de la bibliothèque cliente ZooKeeper ainsi que de nombreuses définitions statiques des types et états d'événement ZooKeeper
  2. org.apache.zookeeper.data : qui définit les caractéristiques associées aux ZNodes, telles que les listes de contrôle d'accès (ACL), les ID, les statistiques, etc.

Il existe également des API Java ZooKeeper utilisées dans l'implémentation de serveur telles que org.apache.zookeeper.server , org.apache.zookeeper.server.quorum et org.apache.zookeeper.server.upgrade .

Cependant, ils sortent du cadre de cet article.

6.2. Connexion à une instance ZooKeeper

Créons maintenant la classe ZKConnection qui sera utilisée pour se connecter et se déconnecter d'un ZooKeeper déjà en cours d'exécution:

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

Pour utiliser un service ZooKeeper, une application doit d'abord instancier un objet de la classe ZooKeeper , qui est la classe principale de la bibliothèque cliente 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.

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 fournit également une élégante API basée sur Java à utiliser dans le code d'application côté client pour une communication transparente avec ZooKeeper ZNodes.

Et comme toujours, toutes les sources de ce didacticiel sont disponibles sur Github.