Skip to content

gventino/GRPC-KVS-GO

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DistributedSystemsKVS

Hybrid system for a generic Key-Value Store.

AUTORES:

Visualização da arquitetura

Arquitetura do Sistema

Vídeo sobre o projeto:

CLIQUE NA IMAGEM OU NO LINK:

https://youtu.be/oa_I9nQufog

Vídeo sobre o projeto

Detalhes de instalação e configuração da linguagem de programação

Certifique-se de ter instalado:

  • Compilador do Go (go) - Versão >= 1.22.2
  • Compilador do Proto (protoc)
  • Gerador de código para go (protoc-gen-go-grpc)
  • Docker instalado (docker) (usamos docker para subir o broker mqtt)
  • Se quiser testar o broker mqtt tenha instalado o mosquitto_sub e mosquitto_pub localmente

Step-by-step guide:

  1. Entre no diretório raíz e execute: go mod tidy Assim o compilador do go irá baixar as dependências necessárias para execução dos módulos do programa.

  2. Após isso, certifique-se de subir o broker mosquitto. Para isso, dirija-se ao diretório Broker e execute o seguinte comando: docker compose up -d

Para testar se o broker está funcionando, execute o script de teste do broker ./Broker/test.sh Ele deve devolver a seguinte mensagem Hello World!.

  1. Agora que o broker mqtt está up, podemos subir nossos servidores kvs, para isto veja a seção Instruções de compilação

Instruções de compilação

  1. Para compilar o servidor, você deve executar o seguinte comando na raiz do projeto: go build -o <NOME_PRO_BINARIO> SuperServer/SuperServer.go

  2. Para executar a build gerada, só executar o seguinte comando: ./<NOME_PRO_BINARIO> --port=:<PORTA>

  3. Se quiser fazer tudo isso em um único comando: ((é mais prático)) go run SuperServer/SuperServer.go --port=:<PORTA>

Uso do servidor

O uso do servidor é super tranquilo, uma vez que tudo foi configurado devidamente (descrito nos tópicos anteriores), basta:

  1. Ou compilar o programa e executar o binario gerado com a tag --port=:<PORTA> (certifique-se que a porta está disponível para uso)

  2. Ou executar go run SuperServer/SuperServer.go --port=:<PORTA>.

OBS : certifique-se que a porta que se deseja usar está disponível para uso.

Organização dos dados com indicação dos formato da(s) tabela(s) hash utilizada(s)

Nosso TAD de KVS está disponível no diretório SuperServer/KVS, vamos investigar a estrutura dos principais modelos utilizados:

Esta é a estrutura da nossa KVS, ela possui um map que mapeia CHAVES(string) para um slice (lista) de Tupla. O RWMutex ali serve para evitar escritas simultâneas, uma vez que os maps do go permitem leitura concorrente por padrão.

type KVS struct {
	hash map[string][]*Tupla
	mu   sync.RWMutex
}

Esta é a estrutura da nossa Tupla, ela foi gerada automaticamente pelo protoc e encontra-se no arquivo SuperServer/KVS/GRPCServerInterface.pb.go

// Retorno de consultas
type Tupla struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Chave  string `protobuf:"bytes,1,opt,name=chave,proto3" json:"chave,omitempty"`    // a chave passada na consulta
	Valor  string `protobuf:"bytes,2,opt,name=valor,proto3" json:"valor,omitempty"`    // valor encontrado
	Versao int32  `protobuf:"varint,3,opt,name=versao,proto3" json:"versao,omitempty"` // versão do valor para a chave
}

Esta é a estrutura do nosso ChaveValor, ela foi gerada automaticamente pelo protoc e encontra-se no arquivo SuperServer/KVS/GRPCServerInterface.pb.go

// Parâmetro de entrada para inserções
type ChaveValor struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Chave string `protobuf:"bytes,1,opt,name=chave,proto3" json:"chave,omitempty"` // a chave
	Valor string `protobuf:"bytes,2,opt,name=valor,proto3" json:"valor,omitempty"` // o valor
}

Esta é a estrutura do nosso ChaveVersao, ela foi gerada automaticamente pelo protoc e encontra-se no arquivo SuperServer/KVS/GRPCServerInterface.pb.go

// Parâmetro de entrada para consultas
type ChaveVersao struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Chave  string `protobuf:"bytes,1,opt,name=chave,proto3" json:"chave,omitempty"`          // a chave pesquisada
	Versao *int32 `protobuf:"varint,2,opt,name=versao,proto3,oneof" json:"versao,omitempty"` // a versão pesquisada (opcional)
}

Esta é a estrutura da nossa Versao, ela foi gerada automaticamente pelo protoc e encontra-se no arquivo SuperServer/KVS/GRPCServerInterface.pb.go

// Versão para snapshot
type Versao struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Versao int32 `protobuf:"varint,1,opt,name=versao,proto3" json:"versao,omitempty"` // a versão pesquisada
}

Temos neste arquivo SuperServer/KVS/GRPCServerInterface_gprc.pb.go a interface do KVSServer, a qual implementamos em SuperServer/KVSServer/KVSServer.go

Interface do KVSServer prevista pelo proto:

// KVSServer is the server API for KVS service.
// All implementations must embed UnimplementedKVSServer
// for forward compatibility.
type KVSServer interface {
	Insere(context.Context, *ChaveValor) (*Versao, error)
	Consulta(context.Context, *ChaveVersao) (*Tupla, error)
	Remove(context.Context, *ChaveVersao) (*Versao, error)
	InsereVarias(grpc.BidiStreamingServer[ChaveValor, Versao]) error
	ConsultaVarias(grpc.BidiStreamingServer[ChaveVersao, Tupla]) error
	RemoveVarias(grpc.BidiStreamingServer[ChaveVersao, Versao]) error
	Snapshot(*Versao, grpc.ServerStreamingServer[Tupla]) error
	mustEmbedUnimplementedKVSServer()
}

Nossa struct que implementa os métodos da interface KVSServer e integra o MQTT para comunicação entre os servidores

// KVSServer implements the KVSServer interface
type KVSServer struct {
	kvs.UnimplementedKVSServer
	kvs  *kvs.KVS
	mqtt *mqtt.Client
}

Descrição das dificuldades

O cliente rust fornecido não sabia lidar direito com as mensagens retornadas pelos nossos servidores nos casos de erro e acabava soltando mensagens de panic que atrapalhava a visualização do resto do teste. Por isso acabamos tirando algumas mensagens de erro. Além disso, sofremos um pouco para evitar duplicações de mensagem entre os servidores via mqtt, o jeito que encontramos foi adicionar um identificador do originador da mensagem, evitando duplicação de mensagens entre os servidores e a reaplicação de métodos nos KVS. Sofremos um pouco pra entender onde seria o melhor lugar de deixar nossa integração com o mqtt também, acabamos optando por deixar no KVSServer, achamos que ficava melhor modularizado assim.

Indicação dos requisitos não implementados

Implementamos tudo que foi requisitado, única coisa que acabamos mudando, foi tirar alguns retornos de mensagem de erro. Fizemos isso pois o cliente rust fornecido para testes não sabia lidar com as mensagens de teste direito, então ele exibia a mensagem, mas logo em seguido dava panic, isso não afetava em nada os nossos servidores, mas os prints do client ficavam bem feios.

Arquivo compile.sh para baixar/instalar dependências, compilar e gerar binários.

Este cara existe na root do projeto, só baixar as seguintes dependências:

  • go
  • docker
  • protoc

Ao executar ./compile.sh <NUMERO_DE_SERVIDORES>. O script irá gerar o número de binarios indicado no comando.

Arquivo server.sh para executar o servidor, recebendo como parâmetro único a porta em que o servidor deve aguardar conexões.

Este cara existe na root do projeto, só baixar as seguintes dependências:

  • go
  • docker
  • protoc

e executar ./server.sh <PORTA>

About

Hybrid system for a generic Key-Value Store.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors