Premiers pas avec Java et Zookeeper

Débuter avec Java et Zookeeper

1. Vue d'ensemble

Apache ZooKeeperis a distributed coordination service qui facilite le développement d'applications distribuées. Il est utilisé par des projets comme Apache Hadoop, HBase etothers pour différents cas d'utilisation tels que l'élection du leader, la gestion de la configuration, la coordination des nœuds, la gestion des baux de serveurs, etc.

Nodes within ZooKeeper cluster store their data in a shared hierarchal namespace 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. Setup

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


    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 telles que des informations sur le statut, des informations de coordination, des informations de localisation, etc. Cette information est stockée 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 toute modification de données ou de liste de contrôle d'accès. En outre, ceci 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 à partir dehere. Avant de faire cela, nous devons nous assurer que nous répondons à la configuration système requise décritehere.

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 documentationhere.

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) de 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’.

Comme nous n'avons passé aucun indicateur, 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'unZNode existant en utilisant l'opérationset.

Par exemple:

set /MyFirstZNode ZNodeValUpdated

Cela mettra à jour les données àMyFirstZNode deZNodeVal àZNodeValUpdated.

Exemple d'API Java ZooKeeper de6.

Examinons maintenant l'API Java 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 de ZooKeeper sont principalement composées de deux packages Java:

  1. org.apache.zookeeper: qui définit la classe principale de la bibliothèque cliente ZooKeeper avec 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.

Des API Java ZooKeeper sont également utilisées dans l’implémentation de serveur, telles queorg.apache.zookeeper.server,org.apache.zookeeper.server.quorum etorg.apache.zookeeper.server.upgrade.

Cependant, ils sortent du cadre de cet article.

6.2. Connexion à une instance ZooKeeper

Créons maintenant la classeZKConnection 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 deZooKeeper class, which is the main class of ZooKeeper client library.

Dans la méthodeconnect, nous instancions une instance de la classeZooKeeper. De plus, nous avons enregistré une méthode de rappel pour traiter lesWatchedEvent de ZooKeeper pour l'acceptation de la connexion et terminer en conséquence la méthodeconnect en utilisant la méthodecountdown deCountDownLatch.

Une fois la connexion à un serveur établie, un ID de session est attribué au client. Pour que la session reste valide, le client doit envoyer périodiquement des pulsations au serveur.

L'application client peut appeler des API ZooKeeper tant que son ID de session reste valide.

6.3. Opérations client

Nous allons maintenant créer une interfaceZKManager qui expose différentes opérations telles que la création d'un ZNode et l'enregistrement de certaines données, la récupération et la mise à jour des données 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;
}

Examinons maintenant la mise en œuvre de l'interface ci-dessus:

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

Dans le code ci-dessus, les appelsconnect etdisconnect sont délégués à la classeZKConnection créée précédemment. Notre méthodecreate est utilisée pour créer un ZNode à un chemin donné à partir des données du tableau d'octets. À des fins de démonstration uniquement, nous avons gardé ACL complètement ouverte.

Une fois créé, le ZNode est persistant et n'est pas supprimé lorsque le client se déconnecte.

La logique pour récupérer les données ZNode de ZooKeeper dans notre méthodegetZNodeData est assez simple. Enfin, avec la méthodeupdate, nous vérifions la présence de ZNode sur un chemin donné et le récupérons s’il existe.

Au-delà, pour la mise à jour des données, nous vérifions d’abord l’existence de ZNode et obtenons la version actuelle. Ensuite, nous invoquons la méthodesetData avec le chemin de ZNode, les données et la version actuelle comme paramètres. ZooKeeper ne mettra à jour les données que si la version transmise correspond à la dernière version.

7. Conclusion

Apache ZooKeeper joue un rôle essentiel en tant que service de coordination distribuée lors du développement d'applications distribuées. Spécifiquement pour les cas d'utilisation tels que le stockage de la configuration partagée, l'élection du nœud maître, etc.

ZooKeeper fournit également une API Java élégante à utiliser dans le code d'application côté client pour une communication transparente avec ZooKeeper ZNodes.

Et comme toujours, toutes les sources de ce tutoriel peuvent être trouvéesover on Github.