Upload
internet
View
102
Download
0
Embed Size (px)
Citation preview
Sistemas DistribuídosWalfredo Cirne & Fubica Brasileiro
http://walfredo.dsc.ufcg.edu.br/cursos/2005/distsis20052
Aula 4: Mais Conceitos Básicos
As figuras que aparecem nesses slides são de Veríssimo&Rodrigues, reproduzidas com o consentimento dos mesmos.
Sincronia
• O que significa sincronia?– envio de mensagens blocking non-blocking – iteração same-time different-time – hardware clock-driven– limite superior para execução de ações
Graus de Sincronia
• Assíncrono– sem limites de tempo para ações
• Síncrono– ações têm limites de tempo conhecidos
• Parcialmente síncrono– ações têm limites de tempo para acontecer,
mas estes são desconhecidos e/ou válidos somente parte do tempo
Qual a gente escolhe?
• Assíncrono– fácil de implementar, mas pouco útil
• Síncrono– muito poderoso, mas conflita com escala,
abertura, interatividade, bom uso dos recursos– usado em sistemas embarcados
• Parcialmente síncrono– muito usado em computação de uso geral– semântica tipicamente não é claramente definida
Ordenação
• Fundamental para que se possa raciocinar sobre sistemas distribuídos
• A priori A posteriori
Precedência [Lamport]
• Se a e b são eventos no mesmo processo e a precede b, então a b
• Se a é o envio da mensagem m e b é a recepção da mensagem m, então a b
• Se a b e b c, então a c
Ordenação de Mensagens
• FIFO: entre quaisquer dois processos, as mensagens são entregues em ordem
• Causal: se envio(m) envio(n), então entrega(m) entrega(n)
• Total: Quaisquer duas mensagens entregues a quaisquer dois processos são entregues na mesma ordem– Fundamental para replicação ativa
• Causal e total são ortogonais!?!
Implementando FIFOLimitações do FIFO
Implementando Ordenação Causal
• Toda mensagem enviada é armazenada em past
• Toda mensagem recebida é armazenada em past
• Toda mensagem m vai acompanhada de past
• Na recepção de m, checa-se primeiro past e caso haja mensagens que ainda não foram entregues, estas são entregues antes que m
Implementação por Relógios Lógicos
• Cada processo mantém o inteiro lclock• Toda mensagem enviada carrega lclock• O envio de uma mensagem incrementa lclock• Mensagens são enviadas usando canais FIFO
• Quando a mensagem m, com lclockm, é entregue, fazemos lclock = max(lclock, lclockm)
• Mensagens só são entregues quando se recebe mensagens de todos os outros processos com lclock maior
• Assumindo que todas as mensagens são broadcast
• Se unicast ou multicast são permitidos, necessita-se de uma matriz no lugar do vetor
Refinamento: Relógios Vetoriais
Canais Ocultos
Relembrando: Exclusão Mútua
• Semáforo S: variável não-negativa inteira que só pode se modificada pelos procedimentos up() e down()
• down(S) se S > 0: decremente Ssenão: bloqueia esperando up(S)
• up(S) se há alguém bloqueado: desbloqueie senão: incremente S
Usando Semáforos
thread P2; statement A; down(mutex); statement B; up(mutex); statement C;end P2;
thread P1; statement X down(mutex); statement Y up(mutex); statement Zend P1;
(* exclusão mútua *)var mutex: semaphore := 1;
Exclusão Mútua via Servidor de Lock
• Necessário para coordenar processos e evitar “colisões”
• Servidor de lock– Interessados em entrar na região crítica mandam
mensagem LOCK para o servidor– O servidor só responde com LOCK-GRANTED para um
processo– Processo envia UNLOCK ao sair da região
• Servidor é ponto único de falhas e possível gargalo de performance
• Falha no cliente também é problema
Exclusão Mútua Distribuída
• Usando um protocolo que garante entrega ordenada total, podemos replicar o servidor de lock em todos os processos do sistema
• Podemos também eleger dinamicamente um líder para função de servidor de lock– Precisamos também pensar em como passar
estado entre lideres, ou então resetar o sistema quando há troca de líder
Eleição de Líder
• Note a necessidade de sincronia para detecção da falha do líder!!
Deadlock
• Deadlock ocorre quando um processo fica esperando por outro
• Para deadlock é necessário ter exclusão mútua, espera circular, obtém-e-espera, não-preempção
• Tudo que você conhece deadlock em sistemas concorrentes vale para sistemas distribuídos, com a complicação que você não tem uma visão global do sistema
Consistência
• Como garantir que alguma propriedade sistêmica é válida?
• Ou seja, como garantir que (ou checar se) a execução do sistema é consistente?
• Para checar, podemos parar o sistema e montar um estado global– Naturalmente, isso é dispendioso– Protocolos de snapshot distribuído são uma
solução bem mais eficiente para o problema
Consenso
• Problema básico para coordenação de processos
• No consenso, cada processo p propõe um valor vp e decide por um valor final fp
• As propriedades de consenso são:– Acordo: p,q que decidem: fp = fq
– Validade: p: fp = vp
– Terminação: Todo processo correto eventualmente decide
Consenso em um Sistema sem Falhas
Acordo sobre Participantes
• Muitas vezes é importante saber quais processos constituem o sistema– Por exemplo, rank e size viabilizam a
computação determinística de uma propriedade por todos os processos
• Conjunto de participantes = Visão
• É fundamental que cada mensagem seja entregue a todos os seus destinatários na mesma visão
Troca de Visão Desincronizada
Atomic Broadcast
• Atomic Broadcast = View Synchrony + Total Order
• Atomic Broadcast =Mudança de visão via entrega de mensagem + Total Order
Determinismo de Replicas
• Atomic broadcast permite implementarmos replicação, desde que as replicas sejam totalmente determinísticas
• Mas, como construir replicas perfeitamente determinísticas?
• Será que um malloc() é determinístico?
Partição do Grupo
• Note que detecção de partição precisa ser entregue como uma mensagem!!
Concorrência
• “A good understanding of the memory consistency model is paramount to building correct programs”
• Consistência atômica– todos os acessos são a mesma memória
• Consistência seqüencial – equivalente a consistência atômica de alguma
execução– indistinguível da consistência atômica se
comunicação é somente via memória
Exemplo: Double-Checked Locking
class Foo { private Helper helper = null; public Helper getHelper() { if (helper == null) synchronized(this) { if (helper == null) helper = new Helper(); } return helper; }}
Modelo de Memória de Java
• Cada thread de Java tem memória local
• Dados inexistentes na memória local são copiados da memória global
• Eventualmente, dados gravados na memória local são refletidos na memória global
• Ao entrar num synchronized, todos os dados da memória local são invalidados
• Ao sair de um synchronized, todos os dados gravados são refletidos globalmente
Outro Exemplo:Objetos Ativos
public class DataRace extends Thread { int a = 0; public DataRace() { this.start(); a = 1; } public void run() { System.out.println(a); }}
Objetos Ativos: O problema é sutil
public class DataRace extends Thread { protected int a = 0; public DataRace() { a = 1; this.start(); }}public class ExtendRace extends DataRace { public ExtendRace() { super(); a = 2; }}
Suporte a Transações
• Transações são uma abstração muito poderosa tipicamente implementadas por banco de dados
• Transações são ACID– Atomicity: tudo ou nada – Consistency: atualizações levam os dados de um
estado consistente para outro estado consistente – Isolation: transações executadas em paralelo não
vêem uma a outra– Durability: é um banco de dados, né?
Transações Distribuídas:Two-phase Commit