Sistemas Distribuídos

Projecto - fase 1


Índice

Entrega: data a combinar

Motivação e Objectivo

Os serviços de indexação são úteis e usados em diversos cenários. Por exemplo, os sistemas de operação tais como o Windows ou macOS possuem serviços de indexação para pesquisar por ficheiros com base no seu conteúdo: Windows search e Spotlight, respectivamente. Existem também repositórios de documentos que além de fornecer armazenamento e acesso a documentos, também mantêm índices para facilitar as buscas sobre os documentos que armazenam, como por exemplo a Wikipedia. Porém, o exemplo mais paradigmático do valor de um serviço de indexação é o alcance e o papel que os motores de busca de páginas web tiveram no modo como a WWW evoluiu e hoje é acedida.

O objectivo do projeto consiste em criar um sistema para indexar e pesquisar informação
sobre documentos.

Um documento neste sistema será modelado por um URL e uma lista de palavras chave. O URL servirá
para indicar a localização do conteúdo do documentos, enquanto que as palavras chaves resumem-no
e servirão para suportar as pesquisas.

O sistema permitirá a um cliente do serviço:

 

Componentes do sistema

O sistema irá conter, no mínimo, os seguintes dois tipos de componentes: servidor de contacto (rendezvous) e servidores de indexação (indexers).

Comportamento

O serviço de indexação será usado pelos clientes do serviço de acordo com os seguintes padrões de acesso.


Interfaces de Programação

Rendezvous Server (Servidor de contacto)

O servidor de contacto (rendezvous) irá manter a lista dos servidores de indexação existentes.

A API REST interface deste serviço será a seguinte:

@Path("/v1/contactos")
public interface RendezVousService {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    List<Contacto> contactos(); // retorna a lista vazia se não houver contactos registados

    @POST
    @Path("/{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    void registar( @PathParam("id") String id, Contacto contacto); // produz "204/No Content" em caso de sucesso, 409/Conflict se o contacto já estiver registado.

    @DELETE
    @Path("/{id}")
    void deregister(String id); // elimina um contacto, produz 204/No Content em caso de sucesso; 404/Not Found se não existe um contacto com o id indicado
}

Indexers (Servidores de indexação)

Cada servidor de indexação é responsável por manter um índice (parcial) dos documentos adicionados ao sistema.

A API REST deste serviço será a seguinte:

@Path("/v1/indexador")
public interface IndexerService {

    @GET
    @Path("/procurar")
    @Produces(MediaType.APPLICATION_JSON)
    List<String> procurar( @QueryParam("pesquisa") String palavras ); // retorna 200 e uma lista de urls que poderá ser vazia. o parâmetro da pesquisa é uma string com uma lista de palavras separadas por +

    @POST
    @Path("/{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    void adicionar( @PathParam("id") String id, Document doc ); // retorna 204 em caso de sucesso, 409 caso o documento já exista no servidor.
      
    @DELETE
    @Path("/{id}")
    void remover( @PathParam("id") String id );
// retorna 204 em caso de sucesso; 404 caso o documento c/ id não exista em nenhum servidor do sistema.
}

 A API SOAP do serviço é a seguinte:

package mz.isctem.indexer.soap;
 
@WebService
public interface IndexerAPI {
   
   
@WebFault
    class InvalidArgumentException
extends Exception {

       
private static final long serialVersionUID = 1L;

        public InvalidArgumentException() {
            super("");
        }
       
        public InvalidArgumentException(String msg) {
            super(msg);
        }
    }

    static
final String NAME="IndexerService";
    static final String NAMESPACE="http://sd2017";
    static final String INTERFACE="api.soap.IndexerAPI";

    /* palavras contem a lista de palavras separada por '+'
     * retorna a lista de urls dos documentos, armazenados neste servidor, onde ocorrem TODAS as palavras; retorna a lista vazia se a pesquisa não produz resultados
     * throws InvalidArgumentException se keywords vale null
     */
    @WebMethod
    List<String> procurar(String palavras) throws InvalidArgumentException;

    /*
     * return true se o documento foi adicionado, false se o documento já existia neste servidor.
     * throws InvalidArgumentException se doc vale null
     */
    @WebMethod
    boolean adicionar(Documento doc) throws InvalidArgumentException ;

    /*
     * return true se o document foi removido globalmente do sistema, falso se não foi encontrado em nenhum servidor do sistema.
     * throws InvalidArgumentException se id vale null
     */
    @WebMethod
    boolean remover(String id) throws InvalidArgumentException ;
}

NOTAS:
  1. Para distinguir entre servidores REST e SOAP, o registo do contacto no servidor de contacto terá nos atributos a chave "type" com "rest" ou "soap" respetivamente. Na falta dessa informação, considera-se que o servidor correspondente a esse contacto implementa a API REST.
  2. Caso esteja presente, o primeiro argumento dos servidores de indexação será o URL completo do servidor de contacto, na forma: http://ip:port/contacts/

Componentes Fornecidos

    Será fornecida uma biblioteca para gerir a informação de indexação mantida por um servidor de indexação. A API desta biblioteca é semelhante à API do serviço de indexação. A informação será apenas mantida em memória. Cada servidor irá possuir a sua própria cópia desta informação.

    Para efeitos de teste e validação, será fornecido um programa de teste. Este programa irá executar uma sequência de operações sobre o sistema e confrontar os resultados obtidos com os esperados.


Funcionalidades

Servidor Rendezvous atualizado

O servidor de contato (rendezvous) deverá manter a informação atualizada na presença de falhas dos servidores de indexação. Após um período de inatividade, a informação guardado no servidor de contato deverá ser descartada.

Descoberta automática do servidor de contato.

Os servidores de indexação utilizarão comunicação multiponto (multicast) para descobrir automaticamente o servidor de contacto. Para isso,
o servidor de contacto deverá responder a uma mensagem multicast (com o conteúdo "rendezvous") com o seu url concreto. O endereço
multicast (e porto) que surportam a descoberta automática podem ser escolhidos livremente.

Versão REST do sistema

Consiste na implementação do sistema baseada exclusivamente em servidores REST.

Versão SOAP do sistema

Consiste na implementação do sistema consistindo num servidor de contacto REST e servidores de indexação SOAP.

Versão REST+SOAP do sistema

Esta versão combina as duas anteriores. Consiste na implementação do sistema consistindo num servidor de contacto REST e
servidores de indexação REST e SOAP e interagem entre si, de forma transparente.


NOTA: Sobre as falhas

    Em relação às falhas dos componentes:

    Em relação aos canais de comunicação, as falhas de comunicação são temporárias.


FASE 2

O objectivo desta base é tornar o sistema mais robusto, aumentando a sua disponibilidade em caso de falha de alguns dos seus compontes.

Havendo dois serviços (serviço de contacto/rendezvous e serviço de indexação, pretende-se que cada um destes serviços seja modificado de
modo a resistir a falhas, por recurso a replicação.

São propostas duas tarefas principais: (1) usar o zookeeper para que a informação guardada pelo servidor de contacto sobreviva a crashes do mesmo. (2) Usar o kafka ou mongo para
replicar o serviço de indexação.

É fornecida uma imagem docker que permite lançar os 3 serviços (zookeeper, kafka e mongo) que ficam prontos a usar.

Mais informação sobre estes sistemas externos auxiliares pode ser consultada em: zookeeper, kafka e mongo.

Servidor Rendezvous replicado + ZOOKEEPER [dificuldade: baixa] 7.5/20 pontos

O estado interno do servidor de contacto passa a ser mantido no zookeeper.

Para tal, as operações sobre o dicionário interno usado no servidor de contacto passam a ser suportadas por operações no zookeeper.
Consulte o exemplo de utilização do zookeeper no seguinte projecto Eclipse.

O resto do sistema deve ficar preparado para suportar mais do que uma instância (réplica) do servidor de contacto. Para isso bastará que
os servidores de indexação façam sempre a descoberta antes de realizar operações sobre o servidor de contacto.

ALTERNATIVA 1

Serviço Indexação + MONGO [dificuldade: baixa] 7.5/20 pontos

O estado interno do servidor de indexação passa a ser mantido na base de dados Mongo. Esta tarefa é sobretudo
um problema de modelação da base de dados NoSQL para suportar a API do serviço de indexação de forma eficiente.
 

Consulte o exemplo de utilização do mongo no seguinte projecto Eclipse.

OPÇÃO VALORATIVA: Serviço Indexação + MONGO [dificuldade: média] +2.5/20 pontos

1) Garantir que as escritas são persistentes. Ou seja, quando o servidor responde ao cliente, tem a certeza que
as escritas foram confirmadas pelo Mongo.

2) Garantir que o serviço de indexação implementa consistência causal. Ou seja, um cliente que faça uma pesquisa
que tenha realizado operações de adição e remoção de documentos, verá os efeitos destas operações num pesquisa posterior.

Sugestão. Consultar na documentação Mongo (https://www.mongodb.com/) os aspectos relacionados com READ E WRITE concerns.

ALTERNATIVA 2

Serviço Indexação + KAFKA [dificuldade: média, pontuação máxima] 12.5/20 pontos

O serviço de indexação utiliza replicação total, onde o seu estado interno é igual é todas as réplicas. Para tal, utiliza o kafka para ordenar
totalmente as operações sobre o índice, segundo o esboço seguinte:

Uma operação de escrita (adicionar ou remover documentos) ao ser recebida pelo servidor é publicada por este para o kafka,
codificando sob a forma de um evento, com um tópico com um dado nome (por exemplo: INDEXADOR).  Todos os servidores
de indexação serão assinantes (subscritores) do referido tópico e executação a operação quando esta for notificada pelo kafka (e não antes).
Como o kafka entregará os eventos/operações pela mesma ordem em todos os servidores/réplicas, a várias cópias do índice passarão
todas pela mesma sequência de estados. Após a execução da operação, o servidor poderá responder ao cliente o resultado da
operação.

Se as pesquisas forem também publicadas no kafka antes de serem executadas, então o serviço de indexação irá suportar
consistência causal. Ou seja, uma pesquisa realizada por um cliente irá incluir os efeitos das operações previamente
realizadas pelo cliente, INDEPENDENTEMENTE, dos servidores onde tenham sido realizadas.

Consulte o exemplo de utilização do kafka no seguinte projecto Eclipse.

Ambiente de Execução e Validação

A validação da solução passará por testar o serviço de indexação num ambiente distribuído suportado por tecnologia Docker.
Os testes envolverão a execução de diversas instâncias dos servidores desenvolvidos, em máquinas distintas, simuladas às custa de contentores docker.
Pretende-se comprovar que o sistema implementa as funcionalidades desejadas e está conforme a especificação.

Relatório
(a completar)