Introdução ao Java e Zookeeper

Introdução ao Java e Zookeeper

1. Visão geral

Apache ZooKeeperis a distributed coordination service que facilita o desenvolvimento de aplicações distribuídas. É usado por projetos como Apache Hadoop, HBase eothers para diferentes casos de uso, como eleição de líder, gerenciamento de configuração, coordenação de nó, gerenciamento de aluguel de servidor, etc.

Nodes within ZooKeeper cluster store their data in a shared hierarchal namespace que é semelhante a um sistema de arquivos padrão ou uma estrutura de dados em árvore.

Neste artigo, exploraremos como usar a API Java do Apache Zookeeper para armazenar, atualizar e excluir informações armazenadas no ZooKeeper.

2. Setup

A versão mais recente da biblioteca Apache ZooKeeper Java pode ser encontradahere:


    org.apache.zookeeper
    zookeeper
    3.4.11

3. Modelo de dados ZooKeeper - ZNode

O ZooKeeper possui um espaço de nomes hierárquico, como um sistema de arquivos distribuído, onde armazena dados de coordenação como informações de status, informações de coordenação, informações de localização etc. Esta informação é armazenada em diferentes nós.

Cada nó em uma árvore ZooKeeper é conhecido como ZNode.

Cada ZNode mantém números de versão e carimbos de data e hora para qualquer alteração de dados ou ACL. Além disso, isso permite ao ZooKeeper validar o cache e coordenar as atualizações.

4. Instalação

4.1. Instalação

A última versão do ZooKeeper pode ser baixada dehere. Antes de fazer isso, precisamos nos certificar de que atendemos aos requisitos do sistema descritos emhere.

4.2. Modo autônomo

Para este artigo, vamos executar o ZooKeeper em modo autônomo, pois requer configuração mínima. Siga as etapas descritas na documentaçãohere.

Observação: no modo autônomo, não há replicação, portanto, se o processo do ZooKeeper falhar, o serviço cairá.

5. Exemplos ZooKeeper CLI

Agora, usaremos a interface de linha de comando (CLI) do ZooKeeper para interagir com o ZooKeeper:

bin/zkCli.sh -server 127.0.0.1:2181

O comando acima inicia uma instância autônoma localmente. Vejamos agora como criar um ZNode e armazenar informações no ZooKeeper:

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

Acabamos de criar um ZNode‘MyFirstZNode’ na raiz do namespace hierárquico do ZooKeeper e gravamos‘ZNodeVal’ nele.

Como não passamos nenhum sinalizador, um ZNode criado será persistente.

Vamos agora emitir um comando‘get' para buscar os dados, bem como os metadados associados a um 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

Podemos atualizar os dados de umZNode existente usando a operaçãoset.

Por exemplo:

set /MyFirstZNode ZNodeValUpdated

Isso atualizará os dados emMyFirstZNode deZNodeVal paraZNodeValUpdated.

6. Exemplo de API Java ZooKeeper

Vamos agora dar uma olhada na API Zookeeper Java e criar um nó, atualizar o nó e recuperar alguns dados.

6.1. Pacotes Java

As ligações do ZooKeeper Java são compostas principalmente por dois pacotes Java:

  1. org.apache.zookeeper: que define a classe principal da biblioteca do cliente ZooKeeper junto com muitas definições estáticas dos tipos de eventos e estados do ZooKeeper

  2. org.apache.zookeeper.data: que define as características associadas a ZNodes, como listas de controle de acesso (ACL), IDs, estatísticas e assim por diante

Existem também APIs Java ZooKeeper que são usadas na implementação de servidor, comoorg.apache.zookeeper.server,org.apache.zookeeper.server.quorum eorg.apache.zookeeper.server.upgrade.

No entanto, eles estão além do escopo deste artigo.

6.2. Conectando-se a uma instância do ZooKeeper

Vamos agora criar a classeZKConnection que será usada para conectar e desconectar de um ZooKeeper já em execução:

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

Para usar um serviço ZooKeeper, um aplicativo deve primeiro instanciar um objeto deZooKeeper class, which is the main class of ZooKeeper client library.

No métodoconnect, estamos instanciando uma instância da classeZooKeeper. Além disso, registramos um método de retorno de chamada para processarWatchedEvent do ZooKeeper para aceitação de conexão e, consequentemente, terminar o métodoconnect usando o métodocountdown deCountDownLatch.

Depois que uma conexão com um servidor é estabelecida, um ID de sessão é atribuído ao cliente. Para manter a sessão válida, o cliente deve enviar periodicamente pulsações para o servidor.

O aplicativo cliente pode chamar as APIs do ZooKeeper desde que seu ID de sessão permaneça válido.

6.3. Operações do cliente

Agora vamos criar uma interfaceZKManager que expõe diferentes operações, como criar um ZNode e salvar alguns dados, buscar e atualizar os dados 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;
}

Vejamos agora a implementação da interface acima:

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

No código acima, as chamadasconnectedisconnect são delegadas à classeZKConnection criada anteriormente. Nosso métodocreate é usado para criar um ZNode em um determinado caminho a partir dos dados da matriz de bytes. Apenas para fins de demonstração, mantivemos o ACL completamente aberto.

Depois de criado, o ZNode é persistente e não é excluído quando o cliente se desconecta.

A lógica para buscar dados ZNode do ZooKeeper em nosso métodogetZNodeData é bastante direta. Finalmente, com o métodoupdate, estamos verificando a presença de ZNode em determinado caminho e obtendo-o, se existir.

Além disso, para atualizar os dados, primeiro verificamos a existência do ZNode e obtemos a versão atual. Em seguida, invocamos o métodosetData com o caminho do ZNode, dados e versão atual como parâmetros. O ZooKeeper atualizará os dados somente se a versão aprovada corresponder à versão mais recente.

7. Conclusão

Ao desenvolver aplicativos distribuídos, o Apache ZooKeeper desempenha um papel crítico como um serviço de coordenação distribuído. Especificamente para casos de uso, como armazenar configuração compartilhada, eleger o nó principal e assim por diante.

O ZooKeeper também fornece uma API elegante baseada em Java para ser usada no código do aplicativo do lado do cliente para comunicação contínua com o ZooKeeper ZNodes.

E como sempre, todas as fontes para este tutorial podem ser encontradasover on Github.