Labs SD >

Apache ZooKeeper

Objetivos

ZooKeeper

O Apache ZooKeeper é um servidor para resolver nomes, fornecer informação de configuração e sincronizar conjuntos de servidores distribuídos.
O seu objetivo é simplificar a gestão de serviços, com propagação fiável de alterações de configuração.

Mais informação: ZooKeeper Documentation

Instalação do ZooKeeper

Utilização

Utilização do ZooKeeper para registo de serviços gRPC

Os endereços de serviços gRPC -- servidor e porto -- devem ser descobertos de forma dinâmica, para evitar que fiquem fixos no código das aplicações. Isto permite que o endereço mude sempre que necessário, sem recompilação dos clientes. Permite também que existam diversas réplicas de servidores para contactar alternativamente.

A interface de clientes ZooKeeper está orientada à monitorização ativa de configurações, o que torna o código bastante verboso.

Para simplificar a utilização do ZooKeeper foi criada a biblioteca ZKNaming que oferece as operações bind (registo), lookup e listRecords (pesquisas). Esta biblioteca torna o código de registo e pesquisa de serviços muito mais sucinto.
O código fonte da biblioteca está disponível para consulta e pode ser modificado, caso seja necessário expor mais funcionalidades do ZooKeeper.

Mais informação: ZKNaming JavaDoc

 


Exercício

O objetivo do exercício desta aula é usar a biblioteca ZKNaming para que o servidor silo-server se registe no ZooKeeper.

  1. Vamos obter a biblioteca ZKNaming e instalar no repositório local do Maven.
    1. Obtenha o codigo da biblioteca zk-naming GitHub
    2. Instalar o módulo no repositório Maven Local:
      Atenção: é necessario que o servidor ZooKeeper já tenha sido iniciado.
      1. cd zk-naming
      2. mvn install
      3. Uma vez instalado o módulo no repositório Maven local, a biblioteca pode ser usada como dependência em qualquer pom.xml.

  2. Relembre o exemplo de gRPC estudado na aula de gRPC
    1. Faça Clone ou Download do branch zk código fonte do exemplo gRPC GitHub
    2. Execute o exemplo seguindo as instruções README.md de cada módulo.
    3. Experimente alterar o porto do servidor no pom.xml e executar novamente ambos os módulos, sem alterar o cliente.
    4. Familiarize-se com o código e responda às seguintes questões:
      1. Onde está o registo do servidor no serviço de nomes?
      2. Como é que o cliente obtém a localização do servidor?
    5. Pode também comparar as diferenças entre o branch e o exemplo de base

  3. Vamos agora adaptar o silo para uma aplicação cliente-servidor que utiliza a biblioteca ZKNaming para registar e procurar serviços distribuídos.
    1. Observe o pom.xml do servidor silo-server:
      1. Adicione a dependência para a biblioteca ZKNaming instalada anteriormente:
        ...
        <!-- ZK Naming -->
        <dependency>
            <groupId>pt.ulisboa.tecnico.sdis</groupId>
            <artifactId>zk-naming</artifactId>
            <version>1.0.3</version>
        </dependency>
        ...							
      2. Confirme as dependências, fazendo:
        mvn dependency:tree

      3. O servidor deverá receber como argumentos o endereço e porto do ZooKeeper, bem como o seu próprio host, port e nome, no formato /grpc/sauron/silo/instance (este nome será referenciado no resto do exercício como path):
        ...
        <properties>
        <zoo.host>localhost</zoo.host>
        <zoo.port>2181</zoo.port>
        
        <!-- instance number -->
        <instance>1</instance>
        
        <server.host>localhost</server.host>
        <server.port>808${instance}</server.port>
        <server.path>/grpc/sauron/silo/${instance}</server.path>
        
        ...
        
        <mainClass>${mainclass}</mainClass>
        <arguments>
            <argument>${zoo.host}</argument>
            <argument>${zoo.port}</argument>
            <argument>${server.host}</argument>
            <argument>${server.port}</argument>
            <argument>${server.path}</argument>
        ...							
        Note a definição da propriedade instance, usada para representar o número de instância do servidor.

    2. Altere o código do servidor, de modo a chamar a biblioteca zk-naming para registar o seu host e port.
      1. Adicionar as seguintes linhas de código ao servidor:
        ...
        ZKNaming zkNaming = null;
        try {
        ...
        	zkNaming = new ZKNaming(zooHost, zooPort);
        	// publish
        	zkNaming.rebind(path, host, port);
        ...
        	// start gRPC server
        ...
        	// await termination
        ...
        } finally  {
        ...
            if (zkNaming != null) {
                // remove
                zkNaming.unbind(path,host,port);
            }
        ...
        }
        							
      2. Atenção: o método unbind deve ser chamado no final do método main do servidor.

  4. Vamos agora alterar os clientes do silo:
    1. Vamos começar por atualizar os pom.xml:
      1. Adicione a dependência para a biblioteca zk-naming no silo-client, no mesmo modo que fez para o servidor.
      2. Adicione ao pom.xml do eye o endereço e porto do ZooKeeper, bem como o path do servidor. Este tem de ser igual ao colocado no pom do servidor.
      3. Proceda de igual modo para o spotter

    2. Altere o código do SiloFrontend de modo a chamar a biblioteca zk-naming para procurar o servidor no ZooKeeper e obter o respectivo host e port.
      1. Adicionar as seguintes linhas de código ao cliente:
        ...
        ZKNaming zkNaming = new ZKNaming(zooHost,zooPort);
        ...
        // lookup
        ZKRecord record = zkNaming.lookup(path);
        String target = record.getURI();
        
        final ManagedChannel channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build();
        ...							
      2. Repare que substituímos o argumento do método forTarget() pelo par host:port obtido através do ZooKeeper.

    3. Execute os clientes e servidor:
      1. Mantenha o servidor ZooKeeper a correr (inicie se estiver parado)
      2. Corra mvn compile exec:java para o servidor e clientes
      3. Experimente correr vários comandos no eye e no spotter
      4. Observe que os clientes comunicam com o servidor, sem ter conhecimento explícito do host:port do mesmo.
        • Pode comprovar, alterando o porto do servidor e testando o cliente sem alterações na sua configuração

    4. E se tivéssemos várias réplicas? Como poderia encontrá-las dinamicamente?
      • Estude a operação listRecords

 


© Docentes de Sistemas Distribuídos, Dep. Eng. Informática, Técnico Lisboa