Skip to content
 
 

Repository files navigation

Banco Distribuído: Lamport, Ricart-Agrawala e Bully

Este repositório implementa um sistema bancário distribuído simples, usado como estudo de caso para três algoritmos clássicos de sistemas distribuídos. É implementado em Python, usando sockets TCP e mensagens em JSON para a comunicação entre os nós.

Atividade 2 disciplina MC714 - Sistemas Distribuídos (Unicamp)

Autoras: Gabriela Jacob e Letícia Lopes

O problema

Vários processos (nós) compartilham um único saldo bancário e podem, a qualquer momento, pedir para sacar ou depositar. Isso levanta três problemas clássicos de sistemas distribuídos que a atividade pede para resolver:

  1. Não existe um relógio global: como ordenar eventos (mensagens, operações) que acontecem em processos diferentes?
  2. O saldo é um recurso compartilhado: como garantir que dois nós não alterem o saldo ao mesmo tempo (exclusão mútua distribuída)?
  3. Os nós podem cair e voltar a qualquer momento: como o sistema continua funcionando sem travar esperando resposta de um nó que já morreu, e como um nó que entra na rede depois descobre o saldo atual?

A solução

Cada nó roda o mesmo script (node.py), com uma thread de servidor (escuta conexões TCP) e um menu interativo (cliente). Toda comunicação é feita por mensagens JSON trocadas em conexões TCP. Os três algoritmos abaixo foram implementados para resolver os problemas listados acima.

Algoritmos implementados

  • Relógio Lógico de Lamport: cada nó mantém um contador (lamport_clock). A cada envio o contador é incrementado; a cada recebimento, o nó atualiza seu relógio para max(relógio_local, relógio_recebido) + 1. É esse timestamp que dá uma ordem total (com desempate por ID de nó) a eventos concorrentes.

  • Exclusão mútua com Ricart-Agrawala: antes de sacar ou depositar, o nó entra em estado WANTED e manda REQUEST_MUTEX (com seu Lamport timestamp) para todos os nós ativos. Cada nó que recebe o pedido responde REPLY_MUTEX na hora, a não ser que ele próprio esteja usando o recurso (ou também querendo usá-lo com prioridade maior - timestamp menor, ou timestamp igual e ID menor); nesse caso, guarda o pedido numa fila de espera e só responde depois de terminar sua própria operação. O nó só executa a operação (e faz o broadcast da alteração de saldo) depois de receber REPLY_MUTEX de todos os outros nós ativos.

  • Eleição de líder com o Algoritmo do Bully: existe sempre um nó líder, responsável por saber quais nós estão vivos (self.ativos). O líder manda PING periódico para cada nó ativo, e cada nó manda PING periódico para o líder atual (para detectar a queda do próprio líder). Quando alguém não responde a tempo:

    • Se foi um nó comum que caiu, o líder remove o nó do array de ativos e avisa todos os outros nós com um NODE_DOWN, para que o Ricart-Agrawala pare de esperar REPLY_MUTEX dele.
    • Se foi o líder que caiu, o nó que percebeu dispara uma eleição (ELECTION/ELECTION_OK/COORDINATOR), seguindo o algoritmo clássico: desafia os nós de ID maior, e quem não é desafiado com sucesso por ninguém se autoproclama líder.
    • Quando um nó novo entra na rede (ou um nó reinicia depois de cair), ele manda um JOIN_REQUEST de broadcast; o líder responde com JOIN_ACCEPT contendo o saldo e o estado atuais, e avisa os demais nós ativos com um NEW_NODE.

Estrutura do projeto

  • config.py: mapeamento de ID de nó para IP e porta.
  • node.py: implementação completa do nó (servidor, cliente, Lamport, Ricart-Agrawala e Bully).
  • teste_concorrencia.py: script auxiliar que dispara duas requisições de mutex simultâneas (saque no Nó 1 e depósito no Nó 2) para demonstrar a disputa do Ricart-Agrawala.
  • docker-compose.yaml e Dockerfile: constroem os nós da rede. Cada nó roda em um contêiner isolado dentro de uma rede virtual (bank_net), utilizando o DNS interno do Docker para resolução de nomes (node1, node2, node3).

Como executar

Nota: é necessário ter o Docker e Docker Compose instalados.

1. Clone o repositório e entre na pasta do projeto:

git clone <url-do-repositorio>
cd MC714-atividade-2

2. Inicializando a Rede

Para construir as imagens e subir os três nós do banco distribuído em background, execute na raiz do projeto:

docker compose up --build

Os nós iniciarão automaticamente, realizarão o procedimento de JOIN e disputarão a eleição inicial do líder usando o algoritmo do Bully.

3. Interagindo com o Menu

Você pode se acoplar (attach) ao terminal de qualquer nó para interagir com o menu do banco:

# Para acessar o menu do Nó 1
docker attach node1

O menu interativo possui a seguinte estrutura:

--- MENU ---
1. Ver saldo
2. Sacar
3. Depositar
4. Sair
5. Ver status da rede (líder e nós ativos)

4. Monitorando os Logs

Para acompanhar as mensagens em tempo real trocadas pelos algoritmos, abra outro terminal e execute:

docker compose logs -f

Como testar os algoritmos

1. Algoritmo de Exclusão Mútua (Ricart-Agrawala):

O container tester roda o script teste_concorrência.py internamente. Esse script espera alguns segundos (para a eleição do líder convergir) e então dispara um saque no Nó 1 e um depósito no Nó 2 ao mesmo tempo. Acompanhe os logs dos 3 nós: o de menor ID vence a disputa e os demais ficam retidos na fila até ele liberar o mutex; ao final, o saldo deve convergir para o mesmo valor nos 3 nós.

2. Algoritmo de Eleição (Bully):

  • Descubra quem é o líder atual consultando o status da rede (Opção 5 do menu de qualquer nó) ou olhando os logs.

  • Derrube o contêiner do nó líder simulando uma queda abrupta de hardware:

    # Supondo que o líder atual seja o Nó 3
    docker compose stop node3
  • Abra o terminal de logs (docker compose logs -f) ou acesse o menu de um dos nós restantes (node1 ou node2). Você observará a detecção da falha via heartbeat e a eleição de um novo líder.

  • Para testar a reentrada, suba o nó antigo novamente, observe-o reentrar na rede recebendo o saldo atual do líder:

    docker compose start node3

About

Repositório de códigos para o projeto da disciplina MC714 - Sistemas Distribuídos.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages